Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
stats.c
Go to the documentation of this file.
1 /* *************************************************************************************
2  Copyright (c) 2021, Lowell D. Thomas
3  All rights reserved.
4 
5  This file is part of APG Version 7.0.
6  APG Version 7.0 may be used under the terms of the BSD 2-Clause License.
7 
8  Redistribution and use in source and binary forms, with or without
9  modification, are permitted provided that the following conditions are met:
10 
11  1. Redistributions of source code must retain the above copyright notice, this
12  list of conditions and the following disclaimer.
13 
14  2. Redistributions in binary form must reproduce the above copyright notice,
15  this list of conditions and the following disclaimer in the documentation
16  and/or other materials provided with the distribution.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24  SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26  OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27  OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 
29 * *************************************************************************************/
39 #include "./apg.h"
40 #ifdef APG_STATS
41 #include <stdio.h>
42 #include <time.h>
43 
44 #include "./lib.h"
45 #include "./parserp.h"
46 
47 static const void* s_vpMagicNumber = (void*)"stats";
48 
52 typedef struct {
53  const char* cpName;
57 } node_stat;
58 
62 typedef struct {
83 } stats;
84 
88 typedef struct {
89  const void* vpValidate;
90  parser* spParserCtx;
92  stats sStats;
94 } stats_ctx;
95 
96 static char* s_cpPageHeader;
97 static char* s_cpPageFooter;
98 static char s_cHits = 'h';
99 static char s_cAlpha = 'a';
100 static int compareNames(const void* l, const void* r);
101 static int compareHits(const void* l, const void* r);
102 
113 void* vpStatsCtor(void* vpParserCtx) {
114  if(!bParserValidate(vpParserCtx)){
115  vExContext();
116  }
117  parser* spParserCtx = (parser*) vpParserCtx;
118  stats_ctx* spCtx;
119  aint ui;
120  spCtx = (stats_ctx*) vpMemAlloc(spParserCtx->vpMem, (aint) sizeof(stats_ctx));
121  memset((void*) spCtx, 0, sizeof(stats_ctx));
122  spCtx->spParserCtx = spParserCtx;
123  spCtx->spException = spMemException(spParserCtx->vpMem);
124  spCtx->sStats.uiRuleCount = spParserCtx->uiRuleCount;
125  spCtx->sStats.uiUdtCount = spParserCtx->uiUdtCount;
126  spCtx->sStats.spRuleStats = (node_stat*) vpMemAlloc(spParserCtx->vpMem,
127  (aint) (spParserCtx->uiRuleCount * (aint) sizeof(node_stat)));
128  memset((void*) spCtx->sStats.spRuleStats, 0, ((size_t) spParserCtx->uiRuleCount * sizeof(node_stat)));
129  for (ui = 0; ui < spParserCtx->uiRuleCount; ui += 1) {
130  spCtx->sStats.spRuleStats[ui].cpName = spParserCtx->spRules[ui].cpRuleName;
131  }
132  if (spParserCtx->uiUdtCount) {
133  spCtx->sStats.spUdtStats = (node_stat*) vpMemAlloc(spParserCtx->vpMem,
134  (aint) (spParserCtx->uiUdtCount * (aint) sizeof(node_stat)));
135  memset((void*) spCtx->sStats.spUdtStats, 0, ((size_t) spParserCtx->uiUdtCount * sizeof(node_stat)));
136  for (ui = 0; ui < spParserCtx->uiUdtCount; ui += 1) {
137  spCtx->sStats.spUdtStats[ui].cpName = spParserCtx->spUdts[ui].cpUdtName;
138  }
139  }
140 
141  // success
142  spParserCtx->vpStats = (void*) spCtx;
143  spCtx->vpValidate = s_vpMagicNumber;
144  return (void*) spCtx;
145 }
146 
156 void vStatsHit(void* vpCtx, const opcode* spOp, aint uiState) {
157  stats_ctx* spCtx = (stats_ctx*) vpCtx;
158  stats* spStats = &spCtx->sStats;
159  node_stat* spNodeStat = NULL;
160  node_stat* spRuleStat = NULL;
161 
162  switch (spOp->sGen.uiId) {
163  case ID_ALT:
164  spNodeStat = &spStats->sAlt;
165  break;
166  case ID_CAT:
167  spNodeStat = &spStats->sCat;
168  break;
169  case ID_REP:
170  spNodeStat = &spStats->sRep;
171  break;
172  case ID_RNM:
173  spNodeStat = &spStats->sRnm;
174  spRuleStat = &spStats->spRuleStats[spOp->sRnm.spRule->uiRuleIndex];
175  break;
176  case ID_TRG:
177  spNodeStat = &spStats->sTrg;
178  break;
179  case ID_TBS:
180  spNodeStat = &spStats->sTbs;
181  break;
182  case ID_TLS:
183  spNodeStat = &spStats->sTls;
184  break;
185  case ID_UDT:
186  spNodeStat = &spStats->sUdt;
187  spRuleStat = &spStats->spUdtStats[spOp->sUdt.spUdt->uiUdtIndex];
188  break;
189  case ID_AND:
190  spNodeStat = &spStats->sAnd;
191  break;
192  case ID_NOT:
193  spNodeStat = &spStats->sNot;
194  break;
195  case ID_BKR:
196  spNodeStat = &spStats->sBkr;
197  break;
198  case ID_BKA:
199  spNodeStat = &spStats->sBka;
200  break;
201  case ID_BKN:
202  spNodeStat = &spStats->sBkn;
203  break;
204  case ID_ABG:
205  spNodeStat = &spStats->sAbg;
206  break;
207  case ID_AEN:
208  spNodeStat = &spStats->sAen;
209  break;
210  default:
211  XTHROW(spCtx->spException, "unrecognized operator ID");
212  break;
213  }
214  spNodeStat->uiHits++;
215  if (uiState == ID_MATCH) {
216  spNodeStat->uiMatch++;
217  } else {
218  spNodeStat->uiNomatch++;
219  }
220  spNodeStat = &spStats->sTotal;
221  spNodeStat->uiHits++;
222  if (uiState == ID_MATCH) {
223  spNodeStat->uiMatch++;
224  } else {
225  spNodeStat->uiNomatch++;
226  }
227  if (spRuleStat) {
228  spRuleStat->uiHits++;
229  if (uiState == ID_MATCH) {
230  spRuleStat->uiMatch++;
231  } else {
232  spRuleStat->uiNomatch++;
233  }
234  }
235 }
236 
246 void vStatsToHtml(void* vpCtx, const char* cpMode, const char* cpFileName) {
247  stats_ctx* spCtx = (stats_ctx*) vpCtx;
248  if(spCtx->vpValidate != s_vpMagicNumber){
249  vExContext();
250  return; // should never return
251  }
252  stats* spStats = &spCtx->sStats;
253  node_stat* spNode;
254  FILE* spOut = stdout;
255  char* cpModeName;
256  char cMode;
257  aint ui;
258 
259  // determine the mode
260  cMode = s_cHits;
261  cpModeName = "hit count"; // default to hit count mode
262  if(cpMode){
263  if (*cpMode == 'a' || *cpMode == 'A') {
264  cpModeName = "alphabetical";
265  cMode = s_cAlpha;
266  }
267  }
268  // open the output file (default is stdout)
269  if (cpFileName) {
270  spOut = fopen(cpFileName, "wb");
271  if(!spOut){
272  XTHROW(spCtx->spException, "stats to HTML unable to open output file");
273  }
274  }
275  // output the page header
276  fprintf(spOut, "%s", s_cpPageHeader);
277  fprintf(spOut, "<h3>Node Statistics<h3/>\n");
278 
279  // open the operators table
280  fprintf(spOut, "%s", "<table class=\"apg-stats\">\n");
281  fprintf(spOut, "<caption>Operators<caption/>\n");
282  fprintf(spOut, "<tr><th>name</th><th>hits</th><th>match</th><th>no match</th><tr>\n");
283  spNode = &spStats->sAlt;
284  fprintf(spOut,
285  "<tr><td><span class=\"apg-remainder\">non-<br>terminals</span></td><td></td><td></td><td></td><tr>\n");
286  fprintf(spOut, "<tr><td>ALT</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
287  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
288  spNode = &spStats->sCat;
289  fprintf(spOut, "<tr><td>CAT</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
290  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
291  spNode = &spStats->sRep;
292  fprintf(spOut, "<tr><td>REP</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
293  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
294  spNode = &spStats->sRnm;
295  fprintf(spOut, "<tr><td>RNM</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
296  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
297  spNode = &spStats->sAnd;
298  fprintf(spOut, "<tr><td>AND</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
299  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
300  spNode = &spStats->sNot;
301  fprintf(spOut, "<tr><td>NOT</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
302  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
303  spNode = &spStats->sBka;
304  fprintf(spOut, "<tr><td>BKA</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
305  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
306  spNode = &spStats->sBkn;
307  fprintf(spOut, "<tr><td>BKN</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
308  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
309  fprintf(spOut, "<tr><td><span class=\"apg-remainder\">terminals</span></td><td></td><td></td><td></td><tr>\n");
310  spNode = &spStats->sTls;
311  fprintf(spOut, "<tr><td>TLS</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
312  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
313  spNode = &spStats->sTbs;
314  fprintf(spOut, "<tr><td>TBS</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
315  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
316  spNode = &spStats->sTrg;
317  fprintf(spOut, "<tr><td>TRG</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
318  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
319  spNode = &spStats->sUdt;
320  fprintf(spOut, "<tr><td>UDT</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
321  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
322  spNode = &spStats->sBkr;
323  fprintf(spOut, "<tr><td>BKR</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
324  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
325  spNode = &spStats->sAbg;
326  fprintf(spOut, "<tr><td>ABG</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
327  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
328  spNode = &spStats->sAen;
329  fprintf(spOut, "<tr><td>AEN</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
330  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
331  spNode = &spStats->sTotal;
332  fprintf(spOut, "<tr><td>total</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", (luint) spNode->uiHits,
333  (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
334 
335  // close the operators table
336  fprintf(spOut, "%s", "</table>\n");
337 
338  // sort the rules
339  node_stat sRuleStats[spStats->uiRuleCount];
340  for (ui = 0; ui < spStats->uiRuleCount; ui += 1) {
341  sRuleStats[ui] = spStats->spRuleStats[ui];
342  }
343  qsort((void*) sRuleStats, (size_t) spStats->uiRuleCount, sizeof(node_stat), compareNames);
344  if (cMode == s_cHits) {
345  qsort((void*) sRuleStats, (size_t) spStats->uiRuleCount, sizeof(node_stat), compareHits);
346  }
347  // open the rules table
348  fprintf(spOut, "<br/>\n");
349  fprintf(spOut, "%s", "<table class=\"apg-stats\">\n");
350  fprintf(spOut, "<caption>Rules: %s<caption/>\n", cpModeName);
351  fprintf(spOut, "<tr><th>name</th><th>hits</th><th>match</th><th>no match</th><tr>\n");
352  for (ui = 0; ui < spStats->uiRuleCount; ui += 1) {
353  spNode = &sRuleStats[ui];
354  if (spNode->uiHits) {
355  fprintf(spOut, "<tr><td>%s</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", spNode->cpName,
356  (luint) spNode->uiHits, (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
357  }
358  }
359 
360  // close the rules table
361  fprintf(spOut, "%s", "</table>\n");
362 
363  if (spStats->uiUdtCount) {
364  // sort the udts
365  node_stat sUdtStats[spStats->uiUdtCount];
366  for (ui = 0; ui < spStats->uiUdtCount; ui += 1) {
367  sUdtStats[ui] = spStats->spUdtStats[ui];
368  }
369  qsort((void*) sUdtStats, (size_t) spStats->uiUdtCount, sizeof(node_stat), compareNames);
370  if (cMode == s_cHits) {
371  qsort((void*) sUdtStats, (size_t) spStats->uiUdtCount, sizeof(node_stat), compareHits);
372  }
373  // open the UDT table
374  fprintf(spOut, "<br/>\n");
375  fprintf(spOut, "%s", "<table class=\"apg-stats\">\n");
376  fprintf(spOut, "<caption>UDTs: %s<caption/>\n", cpModeName);
377  fprintf(spOut, "<tr><th>name</th><th>hits</th><th>match</th><th>no match</th><tr>\n");
378  for (ui = 0; ui < spStats->uiUdtCount; ui += 1) {
379  spNode = &sUdtStats[ui];
380  if (spNode->uiHits) {
381  fprintf(spOut, "<tr><td>%s</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><td>%"PRIuMAX"</td><tr>\n", spNode->cpName,
382  (luint) spNode->uiHits, (luint) spNode->uiMatch, (luint) spNode->uiNomatch);
383  }
384  }
385 
386  // close the UDT table
387  fprintf(spOut, "%s", "</table>\n");
388 
389  }
390 
391  // output the page footer
392  time_t tTime = time(NULL);
393  if (tTime != (time_t)-1) {
394  fprintf(spOut, "<h5>%s</h5>\n", asctime(gmtime(&tTime)));
395  }
396  fprintf(spOut, "%s", s_cpPageFooter);
397  fflush(spOut);
398  if (spOut != stdout) {
399  fclose(spOut);
400  }
401 }
402 
412 void vStatsToAscii(void* vpCtx, const char* cpMode, const char* cpFileName) {
413  stats_ctx* spCtx = (stats_ctx*) vpCtx;
414  if(spCtx->vpValidate != s_vpMagicNumber){
415  vExContext();
416  return; // should never return
417  }
418  stats* spStats = &spCtx->sStats;
419  node_stat* spNode;
420  FILE* spOut = stdout;
421  char* cpModeName;
422  char cMode;
423  aint ui;
424 
425  // determine the mode
426  cMode = s_cHits;
427  cpModeName = "hit count"; // default to hit count mode
428  if(cpMode){
429  if (*cpMode == 'a' || *cpMode == 'A') {
430  cpModeName = "alphabetical";
431  cMode = s_cAlpha;
432  }
433  }
434  // open the output file (default is stdout)
435  if (cpFileName) {
436  spOut = fopen(cpFileName, "wb");
437  if(!spOut){
438  XTHROW(spCtx->spException, "stats to ASCII, can't open output file");
439  }
440  }
441  fprintf(spOut, "NODE STATISTICS\n");
442 
443  // open the operators table
444  fprintf(spOut, "Operators: non-terminals\n");
445  spNode = &spStats->sAlt;
446  char* cpFormats = "| %7s | %7s | %7s | %s\n";
447  char* cpFormat = "| %7"PRIuMAX" | %7"PRIuMAX" | %7"PRIuMAX" | %s\n";
448  fprintf(spOut, cpFormats, "hits", "match", "nomatch", "name");
449  spNode = &spStats->sAlt;
450  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
451  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "ALT");
452  spNode = &spStats->sCat;
453  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
454  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "CAT");
455  spNode = &spStats->sRep;
456  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
457  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "REP");
458  spNode = &spStats->sRnm;
459  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
460  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "RNM");
461  spNode = &spStats->sAnd;
462  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
463  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "AND");
464  spNode = &spStats->sNot;
465  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
466  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "NOT");
467  spNode = &spStats->sBka;
468  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
469  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "BKA");
470  spNode = &spStats->sBkn;
471  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
472  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "BKN");
473 
474  fprintf(spOut, "\n");
475  fprintf(spOut, "Operators: terminals\n");
476  fprintf(spOut, cpFormats, "hits", "match", "nomatch", "name");
477  spNode = &spStats->sTls;
478  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
479  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "TLS");
480  spNode = &spStats->sTbs;
481  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
482  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "TBS");
483  spNode = &spStats->sTrg;
484  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
485  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "TRG");
486  spNode = &spStats->sUdt;
487  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
488  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "UDT");
489  spNode = &spStats->sBkr;
490  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
491  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "BKR");
492  spNode = &spStats->sAbg;
493  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
494  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "ABG");
495  spNode = &spStats->sAen;
496  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
497  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "AEN");
498 
499  fprintf(spOut, "\n");
500  fprintf(spOut, "Operators: total\n");
501  spNode = &spStats->sTotal;
502  fprintf(spOut, cpFormat, (luint) spNode->uiHits,
503  (luint) spNode->uiMatch, (luint) spNode->uiNomatch, "TOTAL");
504 
505  // sort the rules
506  node_stat sRuleStats[spStats->uiRuleCount];
507  for (ui = 0; ui < spStats->uiRuleCount; ui += 1) {
508  sRuleStats[ui] = spStats->spRuleStats[ui];
509  }
510  qsort((void*) sRuleStats, (size_t) spStats->uiRuleCount, sizeof(node_stat), compareNames);
511  if (cMode == s_cHits) {
512  qsort((void*) sRuleStats, (size_t) spStats->uiRuleCount, sizeof(node_stat), compareHits);
513  }
514  // open the rules table
515  fprintf(spOut, "\n");
516  fprintf(spOut, "Rules: %s\n", cpModeName);
517  fprintf(spOut, cpFormats, "hits", "match", "nomatch", "name");
518  for (ui = 0; ui < spStats->uiRuleCount; ui += 1) {
519  spNode = &sRuleStats[ui];
520  if (spNode->uiHits) {
521  fprintf(spOut, cpFormat, (luint) spNode->uiHits, (luint) spNode->uiMatch, (luint) spNode->uiNomatch, spNode->cpName);
522  }
523  }
524 
525  if (spStats->uiUdtCount) {
526  // sort the udts
527  node_stat sUdtStats[spStats->uiUdtCount];
528  for (ui = 0; ui < spStats->uiUdtCount; ui += 1) {
529  sUdtStats[ui] = spStats->spUdtStats[ui];
530  }
531  qsort((void*) sUdtStats, (size_t) spStats->uiUdtCount, sizeof(node_stat), compareNames);
532  if (cMode == s_cHits) {
533  qsort((void*) sUdtStats, (size_t) spStats->uiUdtCount, sizeof(node_stat), compareHits);
534  }
535  // open the UDT table
536  fprintf(spOut, "\n");
537  fprintf(spOut, "UDTs: %s\n", cpModeName);
538  fprintf(spOut, cpFormats, "hits", "match", "nomatch", "name");
539  for (ui = 0; ui < spStats->uiUdtCount; ui += 1) {
540  spNode = &sUdtStats[ui];
541  if (spNode->uiHits) {
542  fprintf(spOut, cpFormat,
543  (luint) spNode->uiHits, (luint) spNode->uiMatch, (luint) spNode->uiNomatch, spNode->cpName);
544  }
545  }
546  }
547  time_t tTime = time(NULL);
548  if (tTime != (time_t)-1) {
549  fprintf(spOut, "\n");
550  fprintf(spOut, "%s\n", asctime(gmtime(&tTime)));
551  }
552  if (spOut != stdout) {
553  fclose(spOut);
554  }
555 }
556 
557 static int compareNames(const void* l, const void* r) {
558  node_stat* spL = (node_stat*) l;
559  node_stat* spR = (node_stat*) r;
560  aint uiLenL = (aint)strlen(spL->cpName);
561  aint uiLenR = (aint)strlen(spR->cpName);
562  aint uiLen = uiLenL < uiLenR ? uiLenL : uiLenR;
563  aint ui;
564  char cL, cR;
565  for(ui = 0; ui < uiLen; ui++){
566  cL = spL->cpName[ui];
567  cR = spR->cpName[ui];
568  if (cL >= 65 && cL <= 90) {
569  cL += 32;
570  }
571  if (cR >= 65 && cR <= 90) {
572  cR += 32;
573  }
574  if (cL < cR) {
575  return -1;
576  }
577  if (cL > cR) {
578  return 1;
579  }
580  }
581  if(uiLenL < uiLenR){
582  return -1;
583  }
584  if(uiLenL > uiLenR){
585  return 1;
586  }
587  return 0;
588 }
589 static int compareHits(const void* l, const void* r) {
590  node_stat* spL = (node_stat*) l;
591  node_stat* spR = (node_stat*) r;
592  if (spL->uiHits < spR->uiHits) {
593  return 1;
594  }
595  if (spL->uiHits > spR->uiHits) {
596  return -1;
597  }
598  return 0;
599 }
600 
601 static char* s_cpPageHeader = "<!DOCTYPE html>\n"
602  "<html lang=\"en\">\n"
603  "<head>\n"
604  "<meta charset=\"utf-8\">\n"
605  "<title>stats</title>\n"
606  "<style>\n"
607  ".apg-mono {\n"
608  " font-family: monospace;\n"
609  "}\n"
610  ".apg-active {\n"
611  " font-weight: bold;\n"
612  " color: #000000;\n"
613  "}\n"
614  ".apg-match {\n"
615  " font-weight: bold;\n"
616  " color: #264BFF;\n"
617  "}\n"
618  ".apg-empty {\n"
619  " font-weight: bold;\n"
620  " color: #0fbd0f;\n"
621  "}\n"
622  ".apg-nomatch {\n"
623  " font-weight: bold;\n"
624  " color: #FF4000;\n"
625  "}\n"
626  ".apg-lh-match {\n"
627  " font-weight: bold;\n"
628  " color: #1A97BA;\n"
629  "}\n"
630  ".apg-lb-match {\n"
631  " font-weight: bold;\n"
632  " color: #5F1687;\n"
633  "}\n"
634  ".apg-remainder {\n"
635  " font-weight: bold;\n"
636  " color: #999999;\n"
637  "}\n"
638  ".apg-ctrl-char {\n"
639  " font-weight: bolder;\n"
640  " font-style: italic;\n"
641  " font-size: .6em;\n"
642  "}\n"
643  ".apg-line-end {\n"
644  " font-weight: bold;\n"
645  " color: #000000;\n"
646  "}\n"
647  ".apg-error {\n"
648  " font-weight: bold;\n"
649  " color: #FF4000;\n"
650  "}\n"
651  ".apg-phrase {\n"
652  " color: #000000;\n"
653  " background-color: #8caae6;\n"
654  "}\n"
655  ".apg-empty-phrase {\n"
656  " color: #0fbd0f;\n"
657  "}\n"
658  "table.apg-state {\n"
659  " font-family: monospace;\n"
660  " margin-top: 5px;\n"
661  " font-size: 11px;\n"
662  " line-height: 130%;\n"
663  " text-align: left;\n"
664  " border: 1px solid black;\n"
665  " border-collapse: collapse;\n"
666  "}\n"
667  "table.apg-state th,\n"
668  "table.apg-state td {\n"
669  " text-align: left;\n"
670  " border: 1px solid black;\n"
671  " border-collapse: collapse;\n"
672  "}\n"
673  "table.apg-state th:nth-last-child(2),\n"
674  "table.apg-state td:nth-last-child(2) {\n"
675  " text-align: right;\n"
676  "}\n"
677  "table.apg-state caption {\n"
678  " font-size: 125%;\n"
679  " line-height: 130%;\n"
680  " font-weight: bold;\n"
681  " text-align: left;\n"
682  "}\n"
683  "table.apg-stats {\n"
684  " font-family: monospace;\n"
685  " margin-top: 5px;\n"
686  " font-size: 11px;\n"
687  " line-height: 130%;\n"
688  " text-align: right;\n"
689  " border: 1px solid black;\n"
690  " border-collapse: collapse;\n"
691  "}\n"
692  "table.apg-stats th,\n"
693  "table.apg-stats td {\n"
694  " text-align: right;\n"
695  " border: 1px solid black;\n"
696  " border-collapse: collapse;\n"
697  "}\n"
698  "table.apg-stats caption {\n"
699  " font-size: 125%;\n"
700  " line-height: 130%;\n"
701  " font-weight: bold;\n"
702  " text-align: left;\n"
703  "}\n"
704  "table.apg-trace {\n"
705  " font-family: monospace;\n"
706  " margin-top: 5px;\n"
707  " font-size: 11px;\n"
708  " line-height: 130%;\n"
709  " text-align: right;\n"
710  " border: 1px solid black;\n"
711  " border-collapse: collapse;\n"
712  "}\n"
713  "table.apg-trace caption {\n"
714  " font-size: 125%;\n"
715  " line-height: 130%;\n"
716  " font-weight: bold;\n"
717  " text-align: left;\n"
718  "}\n"
719  "table.apg-trace th,\n"
720  "table.apg-trace td {\n"
721  " text-align: right;\n"
722  " border: 1px solid black;\n"
723  " border-collapse: collapse;\n"
724  "}\n"
725  "table.apg-trace th:last-child,\n"
726  "table.apg-trace th:nth-last-child(2),\n"
727  "table.apg-trace td:last-child,\n"
728  "table.apg-trace td:nth-last-child(2) {\n"
729  " text-align: left;\n"
730  "}\n"
731  "table.apg-grammar {\n"
732  " font-family: monospace;\n"
733  " margin-top: 5px;\n"
734  " font-size: 11px;\n"
735  " line-height: 130%;\n"
736  " text-align: right;\n"
737  " border: 1px solid black;\n"
738  " border-collapse: collapse;\n"
739  "}\n"
740  "table.apg-grammar caption {\n"
741  " font-size: 125%;\n"
742  " line-height: 130%;\n"
743  " font-weight: bold;\n"
744  " text-align: left;\n"
745  "}\n"
746  "table.apg-grammar th,\n"
747  "table.apg-grammar td {\n"
748  " text-align: right;\n"
749  " border: 1px solid black;\n"
750  " border-collapse: collapse;\n"
751  "}\n"
752  "table.apg-grammar th:last-child,\n"
753  "table.apg-grammar td:last-child {\n"
754  " text-align: left;\n"
755  "}\n"
756  "table.apg-rules {\n"
757  " font-family: monospace;\n"
758  " margin-top: 5px;\n"
759  " font-size: 11px;\n"
760  " line-height: 130%;\n"
761  " text-align: right;\n"
762  " border: 1px solid black;\n"
763  " border-collapse: collapse;\n"
764  "}\n"
765  "table.apg-rules caption {\n"
766  " font-size: 125%;\n"
767  " line-height: 130%;\n"
768  " font-weight: bold;\n"
769  " text-align: left;\n"
770  "}\n"
771  "table.apg-rules th,\n"
772  "table.apg-rules td {\n"
773  " text-align: right;\n"
774  " border: 1px solid black;\n"
775  " border-collapse: collapse;\n"
776  "}\n"
777  "table.apg-rules a {\n"
778  " color: #003399 !important;\n"
779  "}\n"
780  "table.apg-rules a:hover {\n"
781  " color: #8caae6 !important;\n"
782  "}\n"
783  "table.apg-attrs {\n"
784  " font-family: monospace;\n"
785  " margin-top: 5px;\n"
786  " font-size: 11px;\n"
787  " line-height: 130%;\n"
788  " text-align: center;\n"
789  " border: 1px solid black;\n"
790  " border-collapse: collapse;\n"
791  "}\n"
792  "table.apg-attrs caption {\n"
793  " font-size: 125%;\n"
794  " line-height: 130%;\n"
795  " font-weight: bold;\n"
796  " text-align: left;\n"
797  "}\n"
798  "table.apg-attrs th,\n"
799  "table.apg-attrs td {\n"
800  " text-align: center;\n"
801  " border: 1px solid black;\n"
802  " border-collapse: collapse;\n"
803  "}\n"
804  "table.apg-attrs th:nth-child(1),\n"
805  "table.apg-attrs th:nth-child(2),\n"
806  "table.apg-attrs th:nth-child(3) {\n"
807  " text-align: right;\n"
808  "}\n"
809  "table.apg-attrs td:nth-child(1),\n"
810  "table.apg-attrs td:nth-child(2),\n"
811  "table.apg-attrs td:nth-child(3) {\n"
812  " text-align: right;\n"
813  "}\n"
814  "table.apg-attrs a {\n"
815  " color: #003399 !important;\n"
816  "}\n"
817  "table.apg-attrs a:hover {\n"
818  " color: #8caae6 !important;\n"
819  "}\n"
820  "</style>\n"
821  "</head>\n"
822  "<body>\n";
823 static char* s_cpPageFooter = "</body>\n"
824  "</html>\n";
825 
826 #endif /* APG_STATS */
stats::sTotal
node_stat sTotal
The total statistics for all node types.
Definition: stats.c:80
lib.h
This header "#include"s all publid lib headers and other standard headers needed by most objects.
node_stat::uiHits
aint uiHits
Total number of hits.
Definition: stats.c:54
apg.h
The APG header file.
stats::spRuleStats
node_stat * spRuleStats
An array of node statistics for each rule name.
Definition: stats.c:81
ID_RNM
#define ID_RNM
rule name
Definition: parser.h:46
stats::sRep
node_stat sRep
Definition: stats.c:67
stats::sTls
node_stat sTls
Definition: stats.c:70
parserp.h
Private header for the SABNF parser.
stats::sAnd
node_stat sAnd
Definition: stats.c:73
vpStatsCtor
void * vpStatsCtor(void *vpParserCtx)
The statistics object constructor.
Definition: stats.c:113
ID_ALT
#define ID_ALT
alternation
Definition: parser.h:43
ID_BKR
#define ID_BKR
back reference to a previously matched rule or UDT name
Definition: parser.h:58
ID_UDT
#define ID_UDT
user-defined terminal
Definition: parser.h:55
vStatsToHtml
void vStatsToHtml(void *vpCtx, const char *cpMode, const char *cpFileName)
Generates an HTML page displaying the node hit statistics.
Definition: stats.c:246
vExContext
void vExContext()
Handles bad context pointers.
Definition: exception.c:126
stats::sBkr
node_stat sBkr
Definition: stats.c:75
stats::sNot
node_stat sNot
Definition: stats.c:74
ID_NOT
#define ID_NOT
negative look ahead
Definition: parser.h:57
ID_AND
#define ID_AND
positive look ahead
Definition: parser.h:56
stats::spUdtStats
node_stat * spUdtStats
An array of node statistics for each UDT name.
Definition: stats.c:82
XTHROW
#define XTHROW(ctx, msg)
Exception throw macro.
Definition: exception.h:67
stats::sTrg
node_stat sTrg
Definition: stats.c:69
node_stat::cpName
const char * cpName
The node name.
Definition: stats.c:53
aint
uint_fast32_t aint
The APG parser's unsigned integer type.
Definition: apg.h:79
spMemException
exception * spMemException(void *vpCtx)
Get a pointer to this memory objects's exception handler.
Definition: memory.c:174
ID_CAT
#define ID_CAT
concatenation
Definition: parser.h:44
vpMemAlloc
void * vpMemAlloc(void *vpCtx, aint uiBytes)
Allocates memory.
Definition: memory.c:196
ID_TRG
#define ID_TRG
terminal range
Definition: parser.h:47
ID_REP
#define ID_REP
repetition
Definition: parser.h:45
vStatsToAscii
void vStatsToAscii(void *vpCtx, const char *cpMode, const char *cpFileName)
Display the statistics in ASCII format.
Definition: stats.c:412
exception
A structure to describe the type and location of a caught exception.
Definition: exception.h:47
node_stat
Holds the statistics for a single node.
Definition: stats.c:52
stats_ctx::sStats
stats sStats
The totality of all node statistics.
Definition: stats.c:93
ID_MATCH
#define ID_MATCH
indicates a matched phrase parser state on return from parse tree below this node
Definition: parser.h:73
luint
uintmax_t luint
luint is used to cast integers suitable for the %"PRIuMAX" printf format.
Definition: apg.h:133
stats::uiUdtCount
aint uiUdtCount
The number of UDTs in the SABNF grammar.
Definition: stats.c:64
ID_BKA
#define ID_BKA
positive look behind
Definition: parser.h:59
stats_ctx::vpValidate
const void * vpValidate
The "magic number" indicating a valid context.
Definition: stats.c:89
stats
The totality of all node statistics.
Definition: stats.c:62
ID_TLS
#define ID_TLS
terminal literal string
Definition: parser.h:49
stats_ctx::spParserCtx
parser * spParserCtx
Pointer to the parent parser's context.
Definition: stats.c:90
stats_ctx::spException
exception * spException
Pointer to the exception structure for reporting fatal errors back to the parser's catch block scope.
Definition: stats.c:91
stats::sAen
node_stat sAen
Definition: stats.c:79
stats::sUdt
node_stat sUdt
Definition: stats.c:72
stats_ctx
The statistics object context.
Definition: stats.c:88
ID_BKN
#define ID_BKN
negative look behind
Definition: parser.h:60
vStatsHit
void vStatsHit(void *vpCtx, const opcode *spOp, aint uiState)
Collects the statistics for a single node hit.
Definition: stats.c:156
stats::uiRuleCount
aint uiRuleCount
The number of rules in the SABNF grammar.
Definition: stats.c:63
stats::sBkn
node_stat sBkn
Definition: stats.c:77
stats::sAbg
node_stat sAbg
Definition: stats.c:78
ID_ABG
#define ID_ABG
anchor - beginning of string
Definition: parser.h:61
stats::sCat
node_stat sCat
Definition: stats.c:66
stats::sAlt
node_stat sAlt
The statistics for the ALT nodes, ets.
Definition: stats.c:65
stats::sTbs
node_stat sTbs
Definition: stats.c:71
stats::sRnm
node_stat sRnm
Definition: stats.c:68
node_stat::uiNomatch
aint uiNomatch
Number of not matched hits.
Definition: stats.c:56
ID_TBS
#define ID_TBS
terminal binary string
Definition: parser.h:48
node_stat::uiMatch
aint uiMatch
Number of matched hits.
Definition: stats.c:55
bParserValidate
abool bParserValidate(void *vpCtx)
Validate the context pointer of a parser.
Definition: parser.c:422
stats::sBka
node_stat sBka
Definition: stats.c:76
ID_AEN
#define ID_AEN
anchor - end of string
Definition: parser.h:62
APG Version 7.0 is licensed under the 2-Clause BSD License,
an Open Source Initiative Approved License.