/* expression.h */
/* contains the type declarations for expression handling information */
/*
* $Id: expression.c,v 1.1.1.1 2003/11/04 23:34:57 mjames Exp $
*
* $Log: expression.c,v $
* Revision 1.1.1.1 2003/11/04 23:34:57 mjames
* Imported into local repositrory
*
* Revision 1.11 2002/09/30 13:22:38 MJAMES
* Altered the use and creation of partition
* generics (at evaluation time of expressions within the partition )
* This still needs checking, as evaluation of the expression may well be
* delayed until after when the partition generics need to be defined.
*
* Revision 1.10 2002/09/09 15:15:37 mjames
* Altered expression to copy properly
*
* Revision 1.8 2001/11/30 22:19:27 mjames
* Corrected some missing conversion of LBRK to '('.
* Initialised a variable to satisfy GCC.
* Enhanced an error message to give some context.
*
* Revision 1.7 2001/10/31 22:20:04 mjames
* Tidying up problematical comments caused by CVS
* 'intelligent' comment guessing
*
* Revision 1.6 2001/06/06 12:10:23 mjames
* Move from HPUX
*
* Revision 1.5 2001/04/09 14:58:29 mjames
* Added capability to delete generics from specific sockets.
*
* Revision 1.4 2001/04/06 22:47:02 mjames
* Added doc2, the creator of documentation to Vertical scripts uses PERL
*
*
* Also correcting generic behaviour and the printing of Verilog.
*
* Revision 1.3 2000/12/04 13:14:02 mjames
* Imported all of the PCB syntax readers.
*
* Converted "a/b" to mean "a" divided by "b" insted of a single string
* "a/b" in Verilog
*
* Revision 1.2 2000/11/29 21:51:18 mjames
* Fine tuning of software
*
* Revision 1.1.1.1 2000/10/19 21:58:37 mjames
* Mike put it here
*
*
* Revision 1.20 2000/10/12 15:32:18 15:32:18 mjames (Mike James)
* Removed <cr>
*
* Revision 1.19 2000/10/04 10:37:04 10:37:04 mjames (Mike James)
* Modified for Vertical2 : support COMPONENTS and SIGNALS
*
* Revision 1.19 2000/10/04 10:37:04 10:37:04 mjames (Mike James)
* Part of Release PSAVAT01
*
* Revision 1.18 2000/10/02 11:04:12 11:04:12 mjames (Mike James)
* new_vhdl
*
* Revision 1.17 2000/09/27 14:42:12 14:42:12 mjames (Mike James)
* Part of Release Sep_27_ST_2000
*
* Revision 1.16 2000/09/21 10:15:42 10:15:42 mjames (Mike James)
* Part of Release Sep21Alpha
*
* Revision 1.15 2000/08/25 09:57:10 09:57:10 mjames (Mike James)
* Part of Release Aug25_alpha
*
* Revision 1.14 2000/08/16 08:57:27 08:57:27 mjames (Mike James)
* Part of Release CD01_Aug2000
*
* Revision 1.13 2000/08/14 14:45:08 14:45:08 mjames (Mike James)
* Part of Release Aug_14_2000
*
* Revision 1.12 2000/08/11 08:30:28 08:30:28 mjames (Mike James)
* Part of Release Aug_11_2000
*
* Revision 1.11 2000/08/09 10:31:42 10:31:42 mjames (Mike James)
* Part of Release Aug__9_2000
*
* Revision 1.10 2000/05/31 11:42:50 11:42:50 mjames (Mike James)
* Part of Release May_31_2000
*
* Revision 1.9 2000/05/08 17:01:34 17:01:34 mjames (Mike James)
* Part of Release May__8_2000
*
* Revision 1.8 2000/05/08 16:59:27 16:59:27 mjames (Mike James)
* Part of Release May__8_2000
*
* Revision 1.7 2000/05/08 16:57:03 16:57:03 mjames (Mike James)
* Part of Release May__8_2000
*
* Revision 1.6 2000/03/08 16:18:56 16:18:56 mjames (Mike James)
* New version including PC
*
* Revision 1.3 2000/01/20 15:58:42 15:58:42 mjames (Mike James)
* Part of Release R22
*
* Revision 1.2 99/12/22 11:15:23 11:15:23 mjames (Mike James)
* Part of Release Dec_22_1999
*
* Revision 1.1 99/06/25 14:34:45 14:34:45 mjames (Mike James)
* Initial revision
*
* */
#include "expression.h"
#include "acf_yacc.h"
#include "cmdlog.h"
#include "cmdparse.h"
#include "database.h"
#include "generic.h"
#include "vertcl_main.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* place reference to a 'C' variable at the end of the tree branch */
expression_t *compile_variable_reference (int *v, char *s)
{
expression_t *p;
p
= calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = EXP_VAR_REF;
p->left.ip = v;
p->right.s = s;
}
return p;
}
/* place an integer constant at the end of the tree branch */
expression_t *compile_constant (int k)
{
expression_t *p;
p
= calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = EXP_CONSTANT;
p->left.i = k;
p->right.s = NULL;
}
return p;
}
/* place a boolean constant at the end of the tree branch */
expression_t *compile_boolean_constant (int k)
{
expression_t *p;
p
= calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = EXP_BOOLEAN;
p->left.i = k;
p->right.s = NULL;
}
return p;
}
/* this is where the user types some arbitrary string which is a numeric constant */
expression_t *compile_constant_string (int k, char *s)
{
expression_t *p;
p
= calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = EXP_CONSTANT;
p->left.i = k;
p->right.s = ISNULLSTR (s) ? NULL : strdup (s);
}
return p;
}
/* this is where the user types some arbitrary string which is a boolean constant */
expression_t *compile_boolean_constant_string (int k, char *s)
{
expression_t *p;
p
= calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = EXP_BOOLEAN;
p->left.i = k;
p->right.s = ISNULLSTR (s) ? NULL : strdup (s);
}
return p;
}
/* this compiles a reference to the variable */
expression_t *compile_variable (generic_info_t *generic, char *valname)
{
expression_t *p;
p
= calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = EXP_VARIABLE;
p->left.g = generic;
p->right.s = valname;
}
return p;
}
expression_t *compile_string (char *s)
{
expression_t *p;
p
= (expression_t
*) calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = EXP_STRING;
p->left.s = ISNULLSTR (s) ? NULL : strdup (s);
}
return p;
}
expression_t *compile_char (char c)
{
expression_t *p;
p
= (expression_t
*) calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = EXP_CHAR;
p->left.i = c;
}
return p;
}
expression_t *compile_reference (char *s)
{
expression_t *p;
p
= (expression_t
*) calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = EXP_UNDEF_VAR;
p->right.s = ISNULLSTR (s) ? NULL : strdup (s);
}
return p;
}
expression_t *compile_expression (int opcode, expression_t *l, expression_t *r)
{
expression_t *p;
p
= (expression_t
*) calloc (1, sizeof (expression_t
));
if (p)
{
p->opcode = opcode;
p->left.e = l;
p->right.e = r;
}
return p;
}
void print_expression (FILE *f, expression_t *e, generic_print_style recurse_generics)
{
if (!e)
{
return;
}
switch (e->opcode)
{
case EXP_UNDEF_VAR:
if (e->right.s)
break;
case EXP_STRING:
if (e->left.s)
break;
case EXP_CHAR:
break;
case EXP_CONSTANT:
if (e->right.s)
else
break;
case EXP_VAR_REF:
/* if (e->right.s)
fprintf(f,"%s",e->right.s);
else */
break;
case EXP_BOOLEAN:
if (e->right.s)
else
fprintf (f
, "%s", e
->left.
i ? "true" : "false");
break;
case EXP_VARIABLE:
if (e->left.g)
{
if (recurse_generics != NO_RECURSE && e->left.g->expr &&
(recurse_generics == RECURSE_NUMBER ||
e->left.g->expr->opcode != EXP_CONSTANT))
{
print_expression (f, e->left.g->expr, recurse_generics);
}
else
}
else
break;
case UMINUS:
if (e->left.e->opcode != EXP_CONSTANT)
print_expression (f, e->left.e, recurse_generics);
if (e->left.e->opcode != EXP_CONSTANT)
break;
case '~':
if (e->left.e->opcode != EXP_CONSTANT)
print_expression (f, e->left.e, recurse_generics);
if (e->left.e->opcode != EXP_CONSTANT)
break;
case '!':
if (e->left.e->opcode != EXP_CONSTANT)
print_expression (f, e->left.e, recurse_generics);
if (e->left.e->opcode != EXP_CONSTANT)
break;
case '(':
print_expression (f, e->left.e, recurse_generics);
break;
case '+':
case '-':
case '*':
case '/':
case '%':
case '^':
case '?':
case ':':
case '>':
case '<':
case '&':
case '|':
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
case SHL:
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
case SHR:
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
case EQ_EQ:
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
case N_EQ:
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
case LOG_AND:
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
case LOG_OR:
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
case TO_POW:
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
default:
fprintf (f
, "(?? expression ERROR : OPCODE 0x%X)", e
->opcode
);
}
}
/* a range is permitted at the top level of an expression */
/* if there is no expression return */
void print_range_expression (FILE *f, expression_t *e, generic_print_style recurse_generics)
{
if (!e)
return;
switch (e->opcode)
{
case TO:
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
case DOWNTO:
print_expression (f, e->left.e, recurse_generics);
print_expression (f, e->right.e, recurse_generics);
break;
case EXP_VARIABLE:
if (e->left.g)
{
if (recurse_generics != NO_RECURSE)
print_range_expression (f, e->left.g->expr, recurse_generics);
else
}
else
fprintf (f
, "((??%s))", e
->right.
s);
break;
default:
/* handle the expressions down each level of the hierarchy */
/* fprintf(f,"("); */
print_expression (f, e, recurse_generics);
/* fprintf(f,")"); */
}
}
void print_msg_expression (FILE *f, char *s, expression_t *e)
{
print_range_expression (f, e, NO_RECURSE);
}
/* evaluate an integer expression : checking local generics if they are available */
int eval_expression (expression_t *e, generic_info_t **chip_generics)
{
int r = 0;
if (!e)
return 0;
switch (e->opcode)
{
case EXP_CONSTANT:
case EXP_BOOLEAN:
r = e->left.i;
break;
case EXP_VAR_REF:
r = *(e->left.ip);
break;
/* when evaluating expression, if a generic in scope is found then the
generic will be updated : ends up creating and cross-linking a
partition generic */
case EXP_UNDEF_VAR:
{
generic_info_t *gen;
gen = NULL;
if (chip_generics)
{
gen = get_generic_ref (chip_generics, e->right.s);
}
/* search outwards */
if (!gen)
{
gen = get_generic_ref (&global_generics, e->right.s);
}
if (!gen)
{ /* scope is external not local */
expr_ref_t *link;
gen = get_generic_ref (&partition_generics, e->right.s);
/* if no partition generic appears, make one */
if (!gen)
{
generic_info_t newgen;
newgen.typename = "integer";
newgen.name = e->right.s;
newgen.valid = 1;
newgen.expr = compile_constant (0);
newgen.g_type = IS_INTEGER;
newgen.g_class = DEFINED;
gen = set_generic_value (&partition_generics, &newgen);
}
if (gen)
{
link
= calloc (1, sizeof (expr_ref_t
));
}
if (gen && link)
{
link->expr_ref = gen->expr_ref;
gen->expr_ref = link;
link->expr = e;
}
}
if (gen)
{
e->opcode = EXP_VARIABLE;
e->left.g = gen;
/* having located a valid generic then try to link it up */
/* duplicate code borrowed from below. Avoiding 'goto' !! */
eval_gen_expression (gen);
if (gen->g_type == IS_ATTRIBUTE || gen->g_type == IS_INTEGER)
{
r = eval_expression (gen->expr, chip_generics);
#if defined DEBUG_EXPRESSION
printf ("eval %s = %d\n", gen
->name
, r
);
#endif
}
else
{
Log (
LOG_ERROR,
"#Error : generic %s has non integer type (code %d)\n",
gen->name,
gen->g_type);
r = 0;
}
}
else
{
Log (LOG_ERROR, "# symbol '%s' is not defined\n", e->right.s);
}
}
break;
case EXP_VARIABLE:
{
generic_info_t *gen;
gen = e->left.g;
if (gen)
{
eval_gen_expression (gen);
if (gen->g_type == IS_ATTRIBUTE || gen->g_type == IS_INTEGER)
{
r = eval_expression (gen->expr, chip_generics);
#if defined DEBUG_EXPRESSION
printf ("eval %s = %d\n", gen
->name
, r
);
#endif
}
else
{
Log (
LOG_ERROR,
"#Error : generic %s has non integer type (code %d)\n",
gen->name,
gen->g_type);
r = 0;
}
}
else
Log (LOG_ERROR, "#Error : generic '%s' not found\n", e->right.s);
}
break;
case EXP_CHAR:
r = e->left.i;
break;
case EXP_STRING:
r = 0;
break;
case '(':
r = eval_expression (e->left.e, chip_generics);
break;
case UMINUS:
r = 0 - eval_expression (e->left.e, chip_generics);
break;
case '~':
r = ~eval_expression (e->left.e, chip_generics);
break;
case '!':
r = !eval_expression (e->left.e, chip_generics);
break;
case '+':
r = eval_expression (e->left.e, chip_generics) +
eval_expression (e->right.e, chip_generics);
break;
case '-':
r = eval_expression (e->left.e, chip_generics) -
eval_expression (e->right.e, chip_generics);
break;
case '*':
r = eval_expression (e->left.e, chip_generics) *
eval_expression (e->right.e, chip_generics);
break;
case '/':
{
int rhs;
rhs = eval_expression (e->right.e, chip_generics);
if (rhs)
{
r = eval_expression (e->left.e, chip_generics) / rhs;
}
else
{
Log (LOG_ERROR, "# ERROR: Division by 0\n");
r = 0;
};
}
break;
case '%':
{
int rhs;
rhs = eval_expression (e->right.e, chip_generics);
if (rhs)
{
r = eval_expression (e->left.e, chip_generics) % rhs;
}
else
{
Log (LOG_ERROR, "# ERROR: Modulus by 0\n");
r = 0;
};
}
break;
case '^':
r = eval_expression (e->left.e, chip_generics) ^
eval_expression (e->right.e, chip_generics);
break;
case '|':
r = eval_expression (e->left.e, chip_generics) |
eval_expression (e->right.e, chip_generics);
break;
case '&':
r = eval_expression (e->left.e, chip_generics) &
eval_expression (e->right.e, chip_generics);
break;
case '>':
r = eval_expression (e->left.e, chip_generics) >
eval_expression (e->right.e, chip_generics);
break;
case '<':
r = eval_expression (e->left.e, chip_generics) <
eval_expression (e->right.e, chip_generics);
break;
case EQ_EQ:
r = eval_expression (e->left.e, chip_generics) ==
eval_expression (e->right.e, chip_generics);
break;
case N_EQ:
r = eval_expression (e->left.e, chip_generics) !=
eval_expression (e->right.e, chip_generics);
break;
case LOG_OR:
r = eval_expression (e->left.e, chip_generics) ||
eval_expression (e->right.e, chip_generics);
break;
case LOG_AND:
r = eval_expression (e->left.e, chip_generics) &&
eval_expression (e->right.e, chip_generics);
break;
case SHL:
r = eval_expression (e->left.e, chip_generics)
<< eval_expression (e->right.e, chip_generics);
break;
case SHR:
r = eval_expression (e->left.e, chip_generics) >>
eval_expression (e->right.e, chip_generics);
break;
case '?':
r = eval_expression (e->left.e, chip_generics)
? eval_expression (e->right.e->left.e, chip_generics)
: eval_expression (e->right.e->right.e, chip_generics);
break;
case TO_POW:
{
int i, y, x;
x = eval_expression (e->left.e, chip_generics);
y = eval_expression (e->right.e, chip_generics);
if (y == 0) /* x**0 = 1 */
r = 1;
else if (y < 0) /* negative powers */
r = 0;
else
{
i = y; /* limit power */
if (i > 32)
{
Log (
LOG_ERROR,
"arithmetic power of: %d ** %d : %d > 32: limited to 32\n",
x,
y,
y);
i = 32;
}
r = x;
while (--i)
r *= x;
}
}
break;
default:
Log (LOG_ERROR, "#Error : expression : illegal operator (%d)\n", e->opcode);
}
/* printf("(%d)",r); */
return r;
}
int eval_vhdl_expression (expression_t *expr, int *high, int *low)
{
int rc;
generic_info_t **chip_generics =
NULL; /* no local search scope, order of declaration should ensure that
generics are defined before use */
if (!expr)
return 0;
/* my be range at top level in variable */
if (expr->opcode == EXP_VARIABLE)
expr = expr->left.g->expr;
if (!expr)
return 0;
switch (expr->opcode)
{
case TO:
*high = eval_expression (expr->left.e, chip_generics);
*low = eval_expression (expr->right.e, chip_generics);
rc = TO;
break;
case DOWNTO:
*high = eval_expression (expr->left.e, chip_generics);
*low = eval_expression (expr->right.e, chip_generics);
rc = DOWNTO;
break;
default:
/* handle the expressions down each level of the hierarchy */
*high = eval_expression (expr, chip_generics);
*low = *high;
rc = IS_INTEGER;
break;
}
#if defined DEBUG_EXPRESSION
print_msg_expression (stdout, "eval vhdl ", expr);
printf ("high %d low %d rc %d\n", *high
, *low
, rc
);
#endif
return rc;
}
int eval_gen_expression (generic_info_t *gen)
{
#if defined NEED_EVAL_GEN
if (gen)
{
/* printf("Ptr %p: ",exp); */
{
switch (exp->opcode)
{
case EXP_STRING:
gen->valuename = exp->left.s;
gen->g_type = IS_STRING;
gen->valid = 1;
break;
case TO:
gen->valid = 1;
gen->g_type = TO;
break;
case DOWNTO:
gen->valid = 1;
gen->g_type = DOWNTO;
break;
default:
/* handle the expressions down each level of the hierarchy */
gen->valid = 1;
gen->g_type = IS_INTEGER;
}
gen->g_class = DEFINED;
return gen->g_type;
}
}
return NO_VALUE;
#else
return gen->g_type;
#endif
}
/* delete any expression pointed to */
void free_expression (expression_t *ptr)
{
if (!ptr)
return;
switch (ptr->opcode)
{
case EXP_STRING:
if (ptr->left.s)
case EXP_CONSTANT:
case EXP_BOOLEAN:
case EXP_VARIABLE:
case EXP_VAR_REF:
if (ptr->right.s)
free (ptr
->right.
s); /* remove string */
break;
default:
if (ptr->left.e)
free_expression (ptr->left.e);
if (ptr->right.e)
free_expression (ptr->right.e);
break;
}
}
/* copy the expression, fixing up the references to local generic constants
at the same time . Need to */
expression_t *copy_expression (expression_t *ptr, socket_t *skt)
{
expression_t *copy;
if (!ptr)
return NULL;
switch (ptr->opcode)
{
case EXP_CONSTANT:
case EXP_BOOLEAN:
case EXP_STRING:
case EXP_VAR_REF:
case EXP_VARIABLE:
case EXP_CHAR:
return ptr; /* no copy needed as this is a terminal node that cannot change */
break;
/* duplicate undefined references so each induvidual expression is fixed up */
case EXP_UNDEF_VAR:
copy
= calloc (1, sizeof (expression_t
));
*copy = *ptr;
return copy;
break;
default:
return compile_expression (
ptr->opcode,
copy_expression (ptr->left.e, skt),
copy_expression (ptr->right.e, skt));
break;
}
return NULL;
}
struct vhdl *copy_vhdl (vhdl_t *vhdl, socket_t *skt)
{
vhdl_t *new_vhdl;
if (!vhdl)
return NULL;
new_vhdl
= calloc (1, sizeof (vhdl_t
));
*new_vhdl = *vhdl;
new_vhdl->expr = copy_expression (vhdl->expr, skt);
new_vhdl->default_expr = copy_expression (vhdl->default_expr, skt);
#if defined DEBUG_EXPRESSION
printf ("Type = %s\n", vhdl
->basetype
);
print_msg_expression (stdout, "Copied expr", new_vhdl->expr);
print_msg_expression (stdout, "Copied default", new_vhdl->default_expr);
#endif
return new_vhdl;
}