/* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "vertcl_main.h"
#include "expression.h"
#include "generic.h"
#include "database.h"
#include "cmdparse.h"
#include "cmdlog.h"
#include "acf_yacc.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
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;
}