HPCToolkit
MathMLExprParser.cpp
Go to the documentation of this file.
1 // -*-Mode: C++;-*-
2 
3 // * BeginRiceCopyright *****************************************************
4 //
5 // $HeadURL$
6 // $Id$
7 //
8 // --------------------------------------------------------------------------
9 // Part of HPCToolkit (hpctoolkit.org)
10 //
11 // Information about sources of support for research and development of
12 // HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
13 // --------------------------------------------------------------------------
14 //
15 // Copyright ((c)) 2002-2019, Rice University
16 // All rights reserved.
17 //
18 // Redistribution and use in source and binary forms, with or without
19 // modification, are permitted provided that the following conditions are
20 // met:
21 //
22 // * Redistributions of source code must retain the above copyright
23 // notice, this list of conditions and the following disclaimer.
24 //
25 // * Redistributions in binary form must reproduce the above copyright
26 // notice, this list of conditions and the following disclaimer in the
27 // documentation and/or other materials provided with the distribution.
28 //
29 // * Neither the name of Rice University (RICE) nor the names of its
30 // contributors may be used to endorse or promote products derived from
31 // this software without specific prior written permission.
32 //
33 // This software is provided by RICE and contributors "as is" and any
34 // express or implied warranties, including, but not limited to, the
35 // implied warranties of merchantability and fitness for a particular
36 // purpose are disclaimed. In no event shall RICE or contributors be
37 // liable for any direct, indirect, incidental, special, exemplary, or
38 // consequential damages (including, but not limited to, procurement of
39 // substitute goods or services; loss of use, data, or profits; or
40 // business interruption) however caused and on any theory of liability,
41 // whether in contract, strict liability, or tort (including negligence
42 // or otherwise) arising in any way out of the use of this software, even
43 // if advised of the possibility of such damage.
44 //
45 // ******************************************************* EndRiceCopyright *
46 
47 //************************ System Include Files ******************************
48 
49 #include <iostream>
50 using std::cerr;
51 using std::endl;
52 
53 #include <sstream>
54 
55 #include <string>
56 
57 #ifdef NO_STD_CHEADERS
58 # include <stdlib.h>
59 #else
60 # include <cstdlib>
61 using std::atof; // For compatibility with non-std C headers
62 using std::atoi;
63 #endif
64 
65 //************************* User Include Files *******************************
66 
67 #include "MathMLExprParser.hpp"
68 #include "XercesUtil.hpp"
69 
71 
72 #include <lib/support/NaN.h>
73 #include <lib/support/Trace.hpp>
74 #include <lib/support/StrUtil.hpp>
75 
76 //************************ Xerces Include Files ******************************
77 
78 #include <xercesc/util/XMLString.hpp>
79 using XERCES_CPP_NAMESPACE::XMLString;
80 
81 
82 //************************ Forward Declarations ******************************
83 
84 static bool isOperatorNode(DOMNode *node);
85 static bool isOperandNode(DOMNode *node);
86 
87 //****************************************************************************
88 
89 
90 //****************************************************************************
91 //
92 //****************************************************************************
93 
95 {
96 }
97 
98 
100 {
101 }
102 
103 
105 MathMLExprParser::parse(DOMNode* mathMLExpr,
106  const Prof::Metric::Mgr& mMgr)
107 {
108  Prof::Metric::AExpr* exprTree = NULL;
109 
110  int exprs = 0;
111 
112  DOMNode *child = mathMLExpr->getFirstChild();
113  for (; child != NULL; child = child->getNextSibling()) {
114  if (child->getNodeType() == DOMNode::TEXT_NODE) {
115  // DTD ensures this can't contain anything but white space
116  continue;
117  }
118  else if (child->getNodeType() == DOMNode::COMMENT_NODE) {
119  continue;
120  }
121 
122  if (exprs == 1) {
123  throw MathMLExprException("More than one MathML expression specified for COMPUTE");
124  }
125  IFTRACE << child->getNodeType() << endl;
126  exprs++;
127  exprTree = buildEvalTree(child, mMgr, false /*isNum*/);
128  }
129  if (exprs == 0) {
130  throw MathMLExprException("No MathML expression specified for COMPUTE");
131  }
132 
133  return exprTree;
134 }
135 
136 
137 // ----------------------------------------------------------------------
138 // -- Prof::Metric::AExpr* buildEvalTree(DOMNode *node) --
139 // Build an Prof::Metric::AExpr object out of a DOMNode object.
140 // -- params --
141 // node: a DOMNode
142 // -- exception --
143 // An exception of type MathMLExprException could be thrown. If the
144 // ----------------------------------------------------------------------
145 
148  const Prof::Metric::Mgr& mMgr,
149  bool isNum)
150 {
151  static const XMLCh* NUMBER = XMLString::transcode("cn");
152  static const XMLCh* IDENTIFIER = XMLString::transcode("ci");
153 
154  static const XMLCh* APPLY = XMLString::transcode("apply");
155  static const XMLCh* SUBTRACTION = XMLString::transcode("minus");
156  static const XMLCh* ADDITION = XMLString::transcode("plus");
157  static const XMLCh* DIVISION = XMLString::transcode("divide");
158  static const XMLCh* MULTIPLICATION = XMLString::transcode("times");
159  static const XMLCh* EXPONENTIATION = XMLString::transcode("power");
160  static const XMLCh* MAXML = XMLString::transcode("max");
161  static const XMLCh* MINML = XMLString::transcode("min");
162  static const XMLCh* MEAN = XMLString::transcode("mean");
163  static const XMLCh* STDDEV = XMLString::transcode("sdev");
164 
165  // Get the name and value out for convenience
166  const XMLCh* nodeName = node->getNodeName();
167  const XMLCh* nodeValue = node->getNodeValue();
168 
169  switch (node->getNodeType()) {
170 
171  case DOMNode::TEXT_NODE:
172  {
173  Prof::Metric::AExpr* evalNode;
174  if (isNum) { // is a number
175  std::string str = make_string(nodeValue);
176  IFTRACE << "str --" << str << "--" << endl;
177  double val = StrUtil::toDbl(str.c_str());
178  evalNode = new Prof::Metric::Const(val);
179  IFTRACE << "number is --" << val << "--" << endl;
180  }
181  else { // is a variable
182  std::string str = make_string(nodeValue);
183  IFTRACE << "str --" << str << "--" << endl;
184 
185  const Prof::Metric::ADesc* m = mMgr.metric(str);
186  if (!m) {
187  MathML_Throw("Undefined metric '" + str + "' encountered");
188  }
189 
190  IFTRACE << "index --" << m->id() << "--" << endl;
191  evalNode = new Prof::Metric::Var(str, m->id());
192  }
193  return evalNode;
194  }
195 
196  case DOMNode::ELEMENT_NODE: { // ignore all attributes
197 
198  DOMNode *child = node->getFirstChild();
199 
200  // if it is an apply node
201  if (XMLString::equals(nodeName, APPLY)) {
202  IFTRACE << nodeName << endl;
203 
204  // find the node that could be the operator
205  // if it is not, throw a "no operator" exception
206  DOMNode *op = child;
207  while (op != NULL && op->getNodeType() != DOMNode::ELEMENT_NODE)
208  op = op->getNextSibling();
209  if (op == NULL || !isOperatorNode(op)) {
210  throw MathMLExprException("No operator");
211  return NULL;
212  }
213 
214  // if the operator is found
215  int numChildren = 0;
216  child = op;
217  while ((child = child->getNextSibling()) != NULL) {
218  // could be some text between operands, ignore them
219  if (child->getNodeType() == DOMNode::TEXT_NODE) {
220  continue;
221  } else if (child->getNodeType() == DOMNode::COMMENT_NODE) {
222  continue;
223  }
224 
225  if (isOperandNode(child))
226  numChildren++;
227  else {
228  throw MathMLExprException("Invalid expression");
229  return NULL;
230  }
231  }
232  IFTRACE << numChildren << " children" << endl;
233 
234  if (numChildren == 0) {
235  throw MathMLExprException("No operand");
236  return NULL;
237  }
238 
239  Prof::Metric::AExpr** nodes = new Prof::Metric::AExpr*[numChildren];
240 
241  child = op;
242  for (int i = 0; i < numChildren; i++) {
243  do {
244  child = child->getNextSibling();
245  } while (!isOperandNode(child));
246  IFTRACE << "child " << i << " " << child << endl;
247  try {
248  nodes[i] = buildEvalTree(child, mMgr, isNum);
249  }
250  catch (const MathMLExprException& /*ex*/) {
251  for (int j = 0; j < i; j++)
252  delete nodes[j];
253  delete[] nodes;
254  throw;
255  return NULL;
256  }
257  }
258 
259  nodeName = op->getNodeName();
260  if (XMLString::equals(nodeName,SUBTRACTION) && numChildren <= 2) {
261  if (numChildren == 1)
262  return new Prof::Metric::Neg(nodes[0]);
263  return new Prof::Metric::Minus(nodes[0], nodes[1]);
264  }
265  else if (XMLString::equals(nodeName,ADDITION)) {
266  return new Prof::Metric::Plus(nodes, numChildren);
267  }
268  else if (XMLString::equals(nodeName,MULTIPLICATION)) {
269  return new Prof::Metric::Times(nodes, numChildren);
270  }
271  else if (XMLString::equals(nodeName,DIVISION) && numChildren == 2) {
272  return new Prof::Metric::Divide(nodes[0], nodes[1]);
273  }
274  else if (XMLString::equals(nodeName,EXPONENTIATION) && numChildren == 2) {
275  return new Prof::Metric::Power(nodes[0], nodes[1]);
276  }
277  else if (XMLString::equals(nodeName,MAXML)) {
278  return new Prof::Metric::Max(nodes, numChildren);
279  }
280  else if (XMLString::equals(nodeName,MINML)) {
281  return new Prof::Metric::Min(nodes, numChildren);
282  }
283  else if (XMLString::equals(nodeName,MEAN)) {
284  return new Prof::Metric::Mean(nodes, numChildren);
285  }
286  else if (XMLString::equals(nodeName,STDDEV)) {
287  return new Prof::Metric::StdDev(nodes, numChildren);
288  }
289  else {
290  // otherwise, throw an exception and return NULL after the switch
291  for (int i = 0; i < numChildren; i++)
292  delete nodes[i];
293  delete[] nodes;
294  throw MathMLExprException("Unknown operation");
295  }
296  }
297 
298  if (XMLString::equals(nodeName,NUMBER)) {
299  IFTRACE << "--" << child << "--" << endl;
300  Prof::Metric::AExpr* builtNode;
301  try {
302  builtNode = buildEvalTree(child, mMgr, true /*isNum*/);
303  return builtNode;
304  }
305  catch (const MathMLExprException& /*ex*/) {
306  throw;
307  }
308  }
309 
310  if (XMLString::equals(nodeName,IDENTIFIER)) {
311  IFTRACE << "--" << child << "--" << endl;
312  Prof::Metric::AExpr* builtNode;
313  try {
314  builtNode = buildEvalTree(child, mMgr, false /*isNum*/);
315  return builtNode;
316  }
317  catch (const MathMLExprException& /*ex*/) {
318  throw;
319  }
320  }
321 
322  IFTRACE << nodeName << endl;
323  throw MathMLExprException("Unknown node");
324  }
325 
326  case DOMNode::ENTITY_REFERENCE_NODE:
327  {
328  throw MathMLExprException("Entity -- not supported");
329  }
330 
331  case DOMNode::CDATA_SECTION_NODE:
332  {
333  throw MathMLExprException("CDATA -- not supported");
334  }
335 
336  case DOMNode::COMMENT_NODE:
337  {
338  //throw MathMLExprException("Comment -- not supported");
339  break;
340  }
341 
342  default:
343  throw MathMLExprException("Unknown -- not supported");
344  }
345 
346  return NULL; // should not reach
347 }
348 
349 
350 #if 0
351 std::string
352 MathMLExprParser::toString() const
353 {
354  std::ostringstream os;
355  dump(os);
356  return os.str();
357 }
358 
359 
360 std::ostream&
361 MathMLExprParser::dump(std::ostream& os) const
362 {
363  return os;
364 }
365 #endif
366 
367 
368 // ----------------------------------------------------------------------
369 // -- bool isOperatorNode(DOMNode *node) --
370 // Tests whether a DOMNode is one of the operator nodes -- divide,
371 // minus, plus, power and times.
372 // -- params --
373 // node: a DOMNode
374 // ----------------------------------------------------------------------
375 
376 static bool
378 {
379  static const XMLCh* DIVISION = XMLString::transcode("divide");
380  static const XMLCh* SUBTRACTION = XMLString::transcode("minus");
381  static const XMLCh* ADDITION = XMLString::transcode("plus");
382  static const XMLCh* MAXML = XMLString::transcode("max");
383  static const XMLCh* MINML = XMLString::transcode("min");
384  static const XMLCh* EXPONENTIATION = XMLString::transcode("power");
385  static const XMLCh* MULTIPLICATION = XMLString::transcode("times");
386 
387  const XMLCh* nodeName = node->getNodeName();
388 
389  return (XMLString::equals(nodeName,DIVISION) || XMLString::equals(nodeName,SUBTRACTION) ||
390  XMLString::equals(nodeName,ADDITION) || XMLString::equals(nodeName,EXPONENTIATION) ||
391  XMLString::equals(nodeName,MULTIPLICATION) || XMLString::equals(nodeName,MAXML) ||
392  XMLString::equals(nodeName,MINML));
393 }
394 
395 static bool
396 isOperandNode(DOMNode *node)
397 {
398  static const XMLCh* APPLY = XMLString::transcode("apply");
399  static const XMLCh* NUMBER = XMLString::transcode("cn");
400  static const XMLCh* IDENTIFIER = XMLString::transcode("ci");
401 
402  const XMLCh* nodeName = node->getNodeName();
403 
404  return (XMLString::equals(nodeName,APPLY) ||
405  XMLString::equals(nodeName,NUMBER) || XMLString::equals(nodeName,IDENTIFIER));
406 }
407 
double toDbl(const char *str, unsigned *endidx)
Definition: StrUtil.cpp:213
static Prof::Metric::AExpr * parse(DOMNode *mathMLExpr, const Prof::Metric::Mgr &mMgr)
static Prof::Metric::AExpr * buildEvalTree(DOMNode *node, const Prof::Metric::Mgr &mMgr, bool isNum)
static bool isOperandNode(DOMNode *node)
cct_node_t * node
Definition: cct.c:128
static std::string make_string(const XMLCh *const xmlStr)
Definition: XercesUtil.hpp:78
#define IFTRACE
Definition: Trace.hpp:64
#define MathML_Throw(streamArgs)
#define NUMBER(label, num)
static bool isOperatorNode(DOMNode *node)
#define NULL
Definition: ElfHelper.cpp:85
Metric::ADesc * metric(uint i)
Definition: Metric-Mgr.hpp:131