mirror of
https://github.com/autc04/Retro68.git
synced 2024-06-01 00:41:46 +00:00
294 lines
6.5 KiB
C++
294 lines
6.5 KiB
C++
/* Copyright (C) 2021 Free Software Foundation, Inc.
|
|
Contributed by Oracle.
|
|
|
|
This file is part of GNU Binutils.
|
|
|
|
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 3, 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; if not, write to the Free Software
|
|
Foundation, 51 Franklin Street - Fifth Floor, Boston,
|
|
MA 02110-1301, USA. */
|
|
|
|
#include "config.h"
|
|
#include <strings.h>
|
|
#include "DerivedMetrics.h"
|
|
#include "util.h"
|
|
|
|
enum opType
|
|
{
|
|
opNULL,
|
|
opPrimitive,
|
|
opDivide
|
|
};
|
|
|
|
class definition
|
|
{
|
|
public:
|
|
definition();
|
|
~definition();
|
|
char *name;
|
|
char *def;
|
|
opType op;
|
|
definition *arg1;
|
|
definition *arg2;
|
|
int index;
|
|
};
|
|
|
|
definition::definition ()
|
|
{
|
|
name = def = NULL;
|
|
arg1 = arg2 = NULL;
|
|
}
|
|
|
|
definition::~definition ()
|
|
{
|
|
free (name);
|
|
free (def);
|
|
}
|
|
|
|
DerivedMetrics::DerivedMetrics ()
|
|
{
|
|
items = new Vector<definition*>;
|
|
}
|
|
|
|
DerivedMetrics::~DerivedMetrics ()
|
|
{
|
|
Destroy (items);
|
|
}
|
|
|
|
definition *
|
|
DerivedMetrics::add_definition (char *_name, char *_username, char *_def)
|
|
{
|
|
definition *p;
|
|
|
|
// if the name doesn't matter, maybe there is a duplicate we can use
|
|
if (_name == NULL)
|
|
{
|
|
int i;
|
|
Vec_loop (definition*, items, i, p)
|
|
{
|
|
if (strcmp (p->def, _def) == 0)
|
|
return p;
|
|
}
|
|
}
|
|
|
|
p = new definition;
|
|
p->name = dbe_strdup (_name);
|
|
p->def = dbe_strdup (_def);
|
|
|
|
// parse the definition
|
|
if (strchr (_def, '/') == NULL)
|
|
{
|
|
// it's a primitive metric
|
|
p->op = opPrimitive;
|
|
p->arg1 = p->arg2 = NULL;
|
|
|
|
}
|
|
else
|
|
{
|
|
// it's some operation on arguments
|
|
p->op = opDivide;
|
|
char *op_ptr = strchr (p->def, '/');
|
|
*op_ptr = 0;
|
|
p->arg1 = add_definition (NULL, NULL, p->def);
|
|
*op_ptr = '/';
|
|
p->arg2 = add_definition (NULL, NULL, op_ptr + 1);
|
|
}
|
|
p->index = items->size ();
|
|
items->append (p);
|
|
return p;
|
|
}
|
|
|
|
int *
|
|
DerivedMetrics::construct_map (Vector<Metric*> *mitems, BaseMetric::SubType st, char *expr_spec)
|
|
{
|
|
if (items == NULL)
|
|
return NULL;
|
|
int ndm = items->size ();
|
|
if (ndm == 0)
|
|
return NULL;
|
|
int nmetrics = mitems->size ();
|
|
|
|
// allocate arrays for the mapping between derived metrics and requested values
|
|
int *map = (int *) malloc (ndm * sizeof (int));
|
|
|
|
// map derived metrics to requested metrics // EUGENE explain this more clearly
|
|
// 0 means not mapped
|
|
// >0 means primitive metric maps to map-1
|
|
// <0 means derived metric maps to 1-map
|
|
int ndm_requested = 0;
|
|
for (int idm = 0; idm < ndm; idm++)
|
|
{
|
|
definition *defdm = items->fetch (idm);
|
|
map[idm] = 0;
|
|
|
|
// figure out what name to use for this derived metric
|
|
char *dname;
|
|
if (defdm->op == opPrimitive)
|
|
dname = defdm->def;
|
|
else
|
|
{
|
|
dname = defdm->name;
|
|
if (dname == NULL) break;
|
|
}
|
|
|
|
// look for this name among metrics
|
|
int im;
|
|
for (im = 0; im < nmetrics; im++)
|
|
{
|
|
Metric *m = mitems->fetch (im);
|
|
if (strcmp (dname, m->get_cmd ()) == 0 && m->get_subtype () == st)
|
|
// apparent match, but let's check comparison mode
|
|
if (dbe_strcmp (expr_spec, m->get_expr_spec ()) == 0)
|
|
break;
|
|
}
|
|
|
|
// encode the mapping
|
|
if (im >= nmetrics)
|
|
map[idm] = 0; // does not map to requested metrics
|
|
else if (defdm->op == opPrimitive)
|
|
map[idm] = +1 + im; // encode as a positive index
|
|
else
|
|
{
|
|
map[idm] = -1 - im; // encode as a negative index
|
|
ndm_requested++;
|
|
}
|
|
}
|
|
if (ndm_requested == 0)
|
|
{
|
|
free (map);
|
|
map = NULL;
|
|
}
|
|
return map;
|
|
}
|
|
|
|
void
|
|
DerivedMetrics::fill_dependencies (definition *def, int *vec)
|
|
{
|
|
switch (def->op)
|
|
{
|
|
case opPrimitive:
|
|
vec[def->index] = 1;
|
|
break;
|
|
case opDivide:
|
|
fill_dependencies (def->arg1, vec);
|
|
fill_dependencies (def->arg2, vec);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
Vector<definition*> *
|
|
DerivedMetrics::get_dependencies (definition *def)
|
|
{
|
|
int n = items->size ();
|
|
|
|
// zero out a vector representing definitions
|
|
int *vec = (int *) malloc (n * sizeof (int));
|
|
for (int i = 0; i < n; i++)
|
|
vec[i] = 0;
|
|
fill_dependencies (def, vec);
|
|
|
|
// construct the dependency vector
|
|
Vector<definition*> *dependencies = new Vector<definition*>;
|
|
for (int i = 0; i < n; i++)
|
|
if (vec[i] == 1)
|
|
dependencies->append (items->fetch (i));
|
|
free (vec);
|
|
return dependencies;
|
|
}
|
|
|
|
void
|
|
DerivedMetrics::dump (FILE *dis_file, int verbosity)
|
|
{
|
|
int i;
|
|
definition *item;
|
|
|
|
// deal with the possibility that names might be NULL
|
|
const char *UNNAMED = "(unnamed)";
|
|
#define NAME(x) ( (x) ? (x) : UNNAMED)
|
|
|
|
Vec_loop (definition*, items, i, item)
|
|
{
|
|
// at low verbosity, skip over some items
|
|
if (verbosity == 0)
|
|
{
|
|
if (item->name == NULL)
|
|
continue;
|
|
if (strcmp (item->name, item->def) && item->op == opPrimitive)
|
|
continue;
|
|
}
|
|
|
|
// dump the definition
|
|
switch (item->op)
|
|
{
|
|
case opPrimitive:
|
|
fprintf (dis_file, "%s [%s] is a primitive metric\n", NAME (item->name),
|
|
item->def);
|
|
break;
|
|
case opDivide:
|
|
fprintf (dis_file, "%s [%s] = %s [%s] / %s [%s]\n", NAME (item->name),
|
|
item->def, NAME (item->arg1->name), item->arg1->def,
|
|
NAME (item->arg2->name), item->arg2->def);
|
|
break;
|
|
default:
|
|
fprintf (dis_file, "%s [%s] has an unrecognized op %d\n",
|
|
NAME (item->name), item->def, item->op);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
double
|
|
DerivedMetrics::eval_one_item (definition *def, int *map, double *values)
|
|
{
|
|
switch (def->op)
|
|
{
|
|
case opNULL:
|
|
fprintf (stderr, GTXT ("cannot eval NULL expression\n"));
|
|
return 0.;
|
|
case opPrimitive:
|
|
{
|
|
int ival = map[def->index];
|
|
if (ival <= 0) return 0.;
|
|
ival--;
|
|
return values[ival];
|
|
}
|
|
case opDivide:
|
|
{
|
|
double x1 = eval_one_item (def->arg1, map, values);
|
|
double x2 = eval_one_item (def->arg2, map, values);
|
|
if (x2 == 0) return 0.;
|
|
return (x1 / x2);
|
|
}
|
|
default:
|
|
fprintf (stderr, GTXT ("unknown expression\n"));
|
|
return 0.;
|
|
}
|
|
}
|
|
|
|
int
|
|
DerivedMetrics::eval (int *map, double *values)
|
|
{
|
|
for (int i = 0, n = items->size (); i < n; i++)
|
|
{
|
|
if (map[i] < 0)
|
|
{
|
|
int ival = -1 - map[i];
|
|
values[ival] = eval_one_item (items->fetch (i), map, values);
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|