38 static const aint s_uiMaxPhraseLength = 120;
39 static aint uiAcharToHex(
achar acChar,
char* cpHex);
40 static const char* cpIsControl(
achar acChar);
42 static const char* s_caControlChars[33] =
43 {
"NULL",
"SOH",
"STX",
"ETX",
"EOT",
"ENQ",
"ACK",
"BEL",
"BS",
"\\t",
44 "\\n",
"VT",
"FF",
"\\r",
"SO",
"SI",
"DLE",
"DC1",
"DC2",
"DC3",
45 "DC4",
"NAK",
"SYN",
"ETB",
"CAN",
"EM",
"SUB",
"ESC",
"FS",
"GS",
60 static const char* s_cpHtmlHeader;
61 static const char* s_cpHtmlFooter;
66 static void vHtmlSeparator(
trace* spCtx,
aint uiLastIndex);
69 static const char* cpHtmlState(
trace* spTrace,
aint uiState,
aint uiPhraseLength);
70 static const char* cpHtmlOpcode(
trace* spCtx,
const opcode* spOp,
aint uiIndent);
71 static const char* cpHtmlPhrase(
trace* spCtx,
aint uiState,
aint uiOffset,
aint uiPhraseLength);
72 static void vHtmlPhraseUnicode(
html_info* spInfo);
83 static const char* s_cpLineEnd =
"$";
84 static const char* s_cpLineTruncated =
"...";
85 static const char* s_cpEmpty =
"(empty)";
86 static void vAsciiHeader(
trace* spCtx);
87 static void vAsciiSeparator(
trace* spCtx,
aint uiLastIndex);
89 static void vAsciiFooter(
trace* spCtx);
90 static const char* cpAsciiState(
aint uiState,
aint uiPhraseLength);
91 static const char* cpAsciiOpcode(
trace* spCtx,
const opcode* spOp,
aint uiIndent);
92 static const char* cpAsciiPhrase(
trace* spCtx,
aint uiState,
aint uiOffset,
aint uiPhraseLength);
113 vHtmlPpptRecord(spCtx, spRec);
115 vHtmlRecord(spCtx, spRec);
119 vAsciiPpptRecord(spCtx, spRec);
121 vAsciiRecord(spCtx, spRec);
131 vHtmlSeparator(spCtx, uiLastIndex);
133 vAsciiSeparator(spCtx, uiLastIndex);
150 static aint uiAcharToHex(
achar acChar,
char* cpHex){
154 uiReturn = (
aint)sprintf(cpHex,
"x%02"PRIXMAX
"", (
luint) acChar);
157 if(acChar <= 0xFFFF){
158 uiReturn = (
aint)sprintf(cpHex,
"x%04"PRIXMAX
"", (
luint) acChar);
161 if(acChar <= 0xFFFFFF){
162 uiReturn = (
aint)sprintf(cpHex,
"x%06"PRIXMAX
"", (
luint) acChar);
165 if(acChar <= 0xFFFFFFFF){
166 uiReturn = (
aint)sprintf(cpHex,
"x%08"PRIXMAX
"", (
luint) acChar);
169 if(acChar <= 0xFFFFFFFFFF){
170 uiReturn = (
aint)sprintf(cpHex,
"x%010"PRIXMAX
"", (
luint) acChar);
173 if(acChar <= 0xFFFFFFFFFFFF){
174 uiReturn = (
aint)sprintf(cpHex,
"x%012"PRIXMAX
"", (
luint) acChar);
177 if(acChar <= 0xFFFFFFFFFFFFFF){
178 uiReturn = (
aint)sprintf(cpHex,
"x%014"PRIXMAX
"", (
luint) acChar);
181 uiReturn = (
aint)sprintf(cpHex,
"x%016"PRIXMAX
"", (
luint) acChar);
188 static void vAsciiHeader(
trace* spCtx){
189 fprintf(spCtx->
spOut,
"%4s|%3s|%3s|%1s|%3s|%3s|operator matched phrase or remaining unmatched string\n",
"a",
"b",
"c",
"d",
"e",
"f");
192 static void vAsciiSeparator(
trace* spCtx,
aint uiLastIndex){
193 fprintf(spCtx->
spOut,
"Last Index: %"PRIuMAX
"\n", (
luint)uiLastIndex);
202 fprintf(spCtx->
spOut,
"%1s|",
"M");
205 fprintf(spCtx->
spOut,
"%1s|",
"N");
208 fprintf(spCtx->
spOut,
"%1s|",
"E");
211 fprintf(spCtx->
spOut,
"%1s|",
"-");
218 fprintf(spCtx->
spOut,
".");
220 fprintf(spCtx->
spOut,
"PPPT<%s> ", cpAsciiOpcode(spCtx, spRec->
spOpcode, 0));
221 fprintf(spCtx->
spOut,
"%s",
232 fprintf(spCtx->
spOut,
"%s",
235 static void vAsciiFooter(
trace* spCtx){
236 fprintf(spCtx->
spOut,
"\n");
237 fprintf(spCtx->
spOut,
"legend:\n");
238 fprintf(spCtx->
spOut,
"a - line number\n");
239 fprintf(spCtx->
spOut,
"b - tree depth\n");
240 fprintf(spCtx->
spOut,
"c - trace depth\n");
241 fprintf(spCtx->
spOut,
"d - operator state (*)\n");
242 fprintf(spCtx->
spOut,
"e - phrase offset\n");
243 fprintf(spCtx->
spOut,
"f - phrase length\n");
244 fprintf(spCtx->
spOut,
"operator mnemonic - (**)\n");
245 fprintf(spCtx->
spOut,
"matched phrase, if state is M\n");
246 fprintf(spCtx->
spOut,
"(empty), if state is E\n");
247 fprintf(spCtx->
spOut,
"remaining unmatched input string, if state is N or -\n");
248 fprintf(spCtx->
spOut,
"%s - indicates that the input string display has been truncated\n", s_cpLineTruncated);
249 fprintf(spCtx->
spOut,
"%s - indicates the end of string\n", s_cpLineEnd);
250 fprintf(spCtx->
spOut,
" Beware of possible confusion if \"%s\" or \"%s\" exists in input string.\n",
251 s_cpLineTruncated, s_cpLineEnd);
252 fprintf(spCtx->
spOut,
"\n");
253 fprintf(spCtx->
spOut,
"(*) OPERATOR STATE:\n");
254 fprintf(spCtx->
spOut,
" - phrase opened\n");
255 fprintf(spCtx->
spOut,
" M phrase matched\n");
256 fprintf(spCtx->
spOut,
" E phrase empty (matched with length 0)\n");
257 fprintf(spCtx->
spOut,
" N phrase not matched\n");
258 fprintf(spCtx->
spOut,
"\n");
259 fprintf(spCtx->
spOut,
"(**) OPERATOR MNEMONICS:\n");
260 fprintf(spCtx->
spOut,
" original ABNF operators:\n");
261 fprintf(spCtx->
spOut,
"ALT - alternation\n");
262 fprintf(spCtx->
spOut,
"CAT - concatenation\n");
263 fprintf(spCtx->
spOut,
"REP - repetition\n");
264 fprintf(spCtx->
spOut,
"RNM - rule name\n");
265 fprintf(spCtx->
spOut,
"TRG - terminal range\n");
266 fprintf(spCtx->
spOut,
"TLS - terminal literal string (case insensitive)\n");
267 fprintf(spCtx->
spOut,
"TBS - terminal binary string (case sensitive)\n");
268 fprintf(spCtx->
spOut,
"\n");
269 fprintf(spCtx->
spOut,
" SABNF super set operators:\n");
270 fprintf(spCtx->
spOut,
"UDT - user-defined terminal\n");
271 fprintf(spCtx->
spOut,
"AND - positive look ahead\n");
272 fprintf(spCtx->
spOut,
"NOT - negative look ahead\n");
273 fprintf(spCtx->
spOut,
"BKA - positive look behind\n");
274 fprintf(spCtx->
spOut,
"BKN - negative look behind\n");
275 fprintf(spCtx->
spOut,
"BKR - back reference\n");
276 fprintf(spCtx->
spOut,
"ABG - anchor - begin of input string\n");
277 fprintf(spCtx->
spOut,
"AEN - anchor - end of input string\n");
279 static const char* cpAsciiState(
aint uiState,
aint uiPhraseLength) {
280 static const char* cpActive =
"-";
281 static const char* cpMatch =
"M";
282 static const char* cpNomatch =
"N";
283 static const char* cpEmpty =
"E";
284 static const char* cpUnknown =
"U";
292 if (uiPhraseLength == 0) {
299 static const char* cpAsciiOpcode(
trace* spCtx,
const opcode* spOp,
aint uiIndent) {
300 char* cpBuf = spCtx->
cpBuf;
304 for (ui = 0; ui < (int) uiIndent; ui += 1) {
305 n += sprintf(&cpBuf[n],
".");
307 switch (spOp->sGen.uiId) {
310 sprintf(&cpBuf[n],
"%s(%"PRIuMAX
")", cpOp, (
luint) spOp->sAlt.uiChildCount);
314 sprintf(&cpBuf[n],
"%s(%"PRIuMAX
")", cpOp, (
luint) spOp->sCat.uiChildCount);
319 sprintf(&cpBuf[n],
"%s(%"PRIuMAX
"*inf)", cpOp, (
luint) spOp->sRep.uiMin);
321 sprintf(&cpBuf[n],
"%s(%"PRIuMAX
"*%"PRIuMAX
")", cpOp, (
luint) spOp->sRep.uiMin, (
luint) spOp->sRep.uiMax);
326 sprintf(&cpBuf[n],
"%s(%s)", cpOp, spOp->sRnm.spRule->cpRuleName);
330 sprintf(&cpBuf[n],
"%s[x%"PRIXMAX
"-%"PRIXMAX
"]", cpOp, (
luint) spOp->sTrg.acMin, (
luint) spOp->sTrg.acMax);
334 n += sprintf(&cpBuf[n],
"%s[", cpOp);
335 if (spOp->sTbs.uiStrLen > 3) {
336 for (ui = 0; ui < 3; ui += 1) {
338 n += sprintf(&cpBuf[n],
", ");
340 n += sprintf(&cpBuf[n],
"x%"PRIXMAX
"", (
luint) spOp->sTbs.acpStrTbl[ui]);
342 n += sprintf(&cpBuf[n],
", ...");
344 for (ui = 0; ui < spOp->sTbs.uiStrLen; ui += 1) {
346 n += sprintf(&cpBuf[n],
", ");
348 n += sprintf(&cpBuf[n],
"x%"PRIXMAX
"", (
luint) spOp->sTbs.acpStrTbl[ui]);
351 sprintf(&cpBuf[n],
"]");
355 n += sprintf(&cpBuf[n],
"%s(", cpOp);
356 if (spOp->sTls.uiStrLen > 3) {
357 for (ui = 0; ui < 3; ui += 1) {
358 cpBuf[n++]= (char) spOp->sTls.acpStrTbl[ui];
360 n += sprintf(&cpBuf[n],
", ...");
362 for (ui = 0; ui < spOp->sTls.uiStrLen; ui += 1) {
363 cpBuf[n++]= (char) spOp->sTls.acpStrTbl[ui];
366 sprintf(&cpBuf[n],
")");
370 sprintf(&cpBuf[n],
"%s(%s)", cpOp, spOp->sUdt.spUdt->cpUdtName);
374 sprintf(&cpBuf[n],
"%s", cpOp);
378 sprintf(&cpBuf[n],
"%s", cpOp);
382 sprintf(&cpBuf[n],
"%s", cpOp);
386 sprintf(&cpBuf[n],
"%s", cpOp);
390 sprintf(&cpBuf[n],
"%s", cpOp);
394 sprintf(&cpBuf[n],
"%s", cpOp);
398 sprintf(&cpBuf[n],
"%s", cpOp);
402 sprintf(&cpBuf[n],
"%s", cpOp);
410 for(ui = 0; ui < spInfo->
uiStrLen; ui++){
412 if (acChar >= 32 && acChar <= 126){
413 spInfo->
cpBuf[spInfo->
n++] = (char)acChar;
414 }
else if(acChar == 9){
415 spInfo->
n += sprintf(&spInfo->
cpBuf[spInfo->
n],
"\\t");
416 }
else if(acChar == 10){
417 spInfo->
n += sprintf(&spInfo->
cpBuf[spInfo->
n],
"\\n");
418 }
else if(acChar == 13){
419 spInfo->
n += sprintf(&spInfo->
cpBuf[spInfo->
n],
"\\r");
421 spInfo->
n += uiAcharToHex(acChar, &spInfo->
cpBuf[spInfo->
n]);
423 if(spInfo->
n >= s_uiMaxPhraseLength){
431 static const char* cpAsciiPhrase(
trace* spCtx,
aint uiState,
aint uiOffset,
aint uiPhraseLength){
438 if(bAsciiStringAscii(&sInfo)){
439 sInfo.
n += sprintf(&sInfo.
cpBuf[sInfo.
n],
"%s", s_cpLineEnd);
441 sInfo.
n += sprintf(&sInfo.
cpBuf[sInfo.
n],
"%s", s_cpLineTruncated);
446 bAsciiStringAscii(&sInfo);
448 sInfo.
n += sprintf(&sInfo.
cpBuf[sInfo.
n],
"%s", s_cpEmpty);
451 sInfo.
cpBuf[sInfo.
n++] = 10;
459 fprintf(spCtx->
spOut,
"%s", s_cpHtmlHeader);
462 fprintf(spCtx->
spOut,
"%s",
"<table class=\"apg-trace\">\n");
463 fprintf(spCtx->
spOut,
464 "<tr><th>(a)</th><th>(b)</th><th>(c)</th><th>(d)</th><th>(e)</th><th>(f)</th><th>operator</th><th>phrase</th></tr>\n");
466 static void vHtmlSeparator(
trace* spCtx,
aint uiLastIndex){
467 fprintf(spCtx->
spOut,
468 "<tr><td colspan=\"9\">Last Index: %"PRIuMAX
"</td></tr>\n", (
luint)uiLastIndex);
471 fprintf(spCtx->
spOut,
"%s",
"<tr>");
479 fprintf(spCtx->
spOut,
"<td>");
481 fprintf(spCtx->
spOut,
".");
483 fprintf(spCtx->
spOut,
"PPPT<%s></td>", cpHtmlOpcode(spCtx, spRec->
spOpcode, 0));
484 fprintf(spCtx->
spOut,
"<td>%s</td>",
486 fprintf(spCtx->
spOut,
"%s",
"</tr>\n");
489 fprintf(spCtx->
spOut,
"%s",
"<tr>");
497 fprintf(spCtx->
spOut,
"<td>%s</td>",
499 fprintf(spCtx->
spOut,
"%s",
"</tr>\n");
503 fprintf(spCtx->
spOut,
"%s",
"</table>\n");
506 fprintf(spCtx->
spOut,
"%s", s_cpHtmlFooter);
509 static const char* cpHtmlState(
trace* spTrace,
aint uiState,
aint uiPhraseLength) {
511 return "<span class=\"apg-active\">↓ </span>";
514 return "<span class=\"apg-nomatch\">↑N</span>";
517 if (uiPhraseLength == 0) {
518 return "<span class=\"apg-empty\">↑E</span>";
523 return "<span class=\"apg-lh-match\">↑M</span>";
525 return "<span class=\"apg-lb-match\">↑M</span>";
527 return "<span class=\"apg-match\">↑M</span>";
529 return "<span class=\"apg-nomatch\">✘</span>";
531 static const char* cpHtmlOpcode(
trace* spCtx,
const opcode* spOp,
aint uiIndent) {
532 char* cpBuf = spCtx->
cpBuf;
536 for (ui = 0; ui < (int) uiIndent; ui += 1) {
537 n += sprintf(&cpBuf[n],
".");
539 switch (spOp->sGen.uiId) {
542 sprintf(&cpBuf[n],
"%s(%"PRIuMAX
")", cpOp, (
luint) spOp->sAlt.uiChildCount);
546 sprintf(&cpBuf[n],
"%s(%"PRIuMAX
")", cpOp, (
luint) spOp->sCat.uiChildCount);
551 sprintf(&cpBuf[n],
"%s(%"PRIuMAX
"*∞)", cpOp, (
luint) spOp->sRep.uiMin);
553 sprintf(&cpBuf[n],
"%s(%"PRIuMAX
"*%"PRIuMAX
")", cpOp, (
luint) spOp->sRep.uiMin, (
luint) spOp->sRep.uiMax);
558 sprintf(&cpBuf[n],
"%s(%s)", cpOp, spOp->sRnm.spRule->cpRuleName);
562 sprintf(&cpBuf[n],
"%s[x%"PRIXMAX
"-%"PRIXMAX
"]", cpOp, (
luint) spOp->sTrg.acMin, (
luint) spOp->sTrg.acMax);
566 n += sprintf(&cpBuf[n],
"%s[", cpOp);
567 if (spOp->sTbs.uiStrLen > 3) {
568 for (ui = 0; ui < 3; ui += 1) {
570 n += sprintf(&cpBuf[n],
", ");
572 n += sprintf(&cpBuf[n],
"x%"PRIXMAX
"", (
luint) spOp->sTbs.acpStrTbl[ui]);
574 n += sprintf(&cpBuf[n],
", ...");
576 for (ui = 0; ui < spOp->sTbs.uiStrLen; ui += 1) {
578 n += sprintf(&cpBuf[n],
", ");
580 n += sprintf(&cpBuf[n],
"x%"PRIXMAX
"", (
luint) spOp->sTbs.acpStrTbl[ui]);
583 sprintf(&cpBuf[n],
"]");
587 n += sprintf(&cpBuf[n],
"%s(", cpOp);
588 if (spOp->sTls.uiStrLen > 3) {
589 for (ui = 0; ui < 3; ui += 1) {
590 n += sprintf(&cpBuf[n],
"&#%"PRIuMAX
";", (
luint) spOp->sTls.acpStrTbl[ui]);
592 n += sprintf(&cpBuf[n],
", ...");
594 for (ui = 0; ui < spOp->sTls.uiStrLen; ui += 1) {
595 n += sprintf(&cpBuf[n],
"&#%"PRIuMAX
";", (
luint) spOp->sTls.acpStrTbl[ui]);
598 sprintf(&cpBuf[n],
")");
602 sprintf(&cpBuf[n],
"%s(%s)", cpOp, spOp->sUdt.spUdt->cpUdtName);
606 sprintf(&cpBuf[n],
"%s", cpOp);
610 sprintf(&cpBuf[n],
"%s", cpOp);
614 sprintf(&cpBuf[n],
"%s", cpOp);
618 sprintf(&cpBuf[n],
"%s", cpOp);
622 sprintf(&cpBuf[n],
"%s", cpOp);
626 sprintf(&cpBuf[n],
"%s", cpOp);
630 sprintf(&cpBuf[n],
"%s", cpOp);
634 sprintf(&cpBuf[n],
"%s", cpOp);
645 static void vHtmlPhraseUnicode(
html_info* spInfo){
648 const char* cpControl;
651 n += sprintf(&cpBuf[n],
"%s", spInfo->
cpEmpty);
656 n += sprintf(&cpBuf[n],
"<span class=\"apg-lh-match\">");
658 n += sprintf(&cpBuf[n],
"<span class=\"apg-lb-match\">");
662 n += sprintf(&cpBuf[n],
"<span class=\"apg-match\">");
664 for (ui = 0; ui < spInfo->
uiMatched; ui++, acpOut++) {
665 cpControl = cpIsControl(*acpOut);
667 n += sprintf(&cpBuf[n],
"<span class=\"apg-ctrl-char\">%s</span>", cpControl);
668 }
else if(*acpOut == 32){
669 n += sprintf(&cpBuf[n],
" ");
670 }
else if(bIsUnicode(*acpOut)){
671 n += sprintf(&cpBuf[n],
"&#%"PRIuMAX
";", (
luint) *acpOut);
673 n += (int)uiAcharToHex(*acpOut, &cpBuf[n]);
676 n += sprintf(&cpBuf[n],
"</span>");
679 n += sprintf(&cpBuf[n],
"<span class=\"apg-remainder\">");
680 for (ui = 0; ui < spInfo->
uiRemainder; ui++, acpOut++) {
681 cpControl = cpIsControl(*acpOut);
683 n += sprintf(&cpBuf[n],
"<span class=\"apg-ctrl-char\">%s</span>", cpControl);
684 }
else if(*acpOut == 32){
685 n += sprintf(&cpBuf[n],
" ");
686 }
else if(bIsUnicode(*acpOut)){
687 n += sprintf(&cpBuf[n],
"&#%"PRIuMAX
";", (
luint) *acpOut);
689 n += (int)uiAcharToHex(*acpOut, &cpBuf[n]);
692 n += sprintf(&cpBuf[n],
"</span>");
694 n += sprintf(&cpBuf[n],
"%s", spInfo->
cpLastChar);
696 static const char* cpHtmlPhrase(
trace* spCtx,
aint uiState,
aint uiOffset,
aint uiPhraseLength) {
697 aint uiMatchedLen, uiRemainder, uiLeft;
699 char *cpEmpty, *cpLastChar;
700 if (uiState ==
ID_MATCH && uiPhraseLength == 0) {
701 cpEmpty =
"<span class=\"apg-empty\">𝜀</span>";
705 uiLeft = spCtx->
spParserCtx->uiSubStringEnd - uiOffset;
706 cpLastChar =
"<span class=\"apg-line-end\">•</span>";
707 if (uiLeft >= s_uiMaxPhraseLength) {
708 uiLeft = s_uiMaxPhraseLength;
709 cpLastChar =
"<span class=\"apg-line-end\">…</span>";
713 uiMatchedLen = uiPhraseLength < uiLeft ? uiPhraseLength : uiLeft;
715 uiLeft -= uiMatchedLen;
716 uiRemainder = s_uiMaxPhraseLength - uiMatchedLen;
717 if(uiLeft < uiRemainder){
718 uiRemainder = uiLeft;
728 vHtmlPhraseUnicode(&sInfo);
732 static const char* cpIsControl(
achar acChar){
733 if(acChar >= 0 && acChar <=31){
734 return s_caControlChars[(
luint)acChar];
737 return s_caControlChars[32];
742 if(acChar >= 33 && acChar <=126){
745 if(acChar >= 0x80 && acChar <=0xd7ff){
748 if(acChar >= 0xe000 && acChar <= 0xffff){
754 static const char* s_cpHtmlHeader =
"<!DOCTYPE html>\n"
755 "<html lang=\"en\">\n"
757 "<meta charset=\"utf-8\">\n"
758 "<title>trace</title>\n"
761 " font-family: monospace;\n"
764 " font-weight: bold;\n"
768 " font-weight: bold;\n"
769 " background-color: #6680FF;\n"
773 " font-weight: bold;\n"
774 " background-color: #0fbd0f;\n"
778 " font-weight: bold;\n"
779 " background-color: #FF4000;\n"
783 " font-weight: bold;\n"
784 " background-color: #D966FF;\n"
788 " font-weight: bold;\n"
789 " background-color: #FF944D;\n"
793 " font-weight: bold;\n"
794 " color: gray;/* #999999 */\n"
797 " font-weight: bolder;\n"
798 " font-style: italic;\n"
799 " font-size: .8em;\n"
803 " font-weight: bold;\n"
807 " font-weight: bold;\n"
812 " background-color: #8caae6;\n"
814 ".apg-empty-phrase {\n"
817 "table.apg-state {\n"
818 " font-family: monospace;\n"
819 " margin-top: 5px;\n"
820 " font-size: 11px;\n"
821 " line-height: 130%;\n"
822 " text-align: left;\n"
823 " border: 1px solid black;\n"
824 " border-collapse: collapse;\n"
826 "table.apg-state th,\n"
827 "table.apg-state td {\n"
828 " text-align: left;\n"
829 " border: 1px solid black;\n"
830 " border-collapse: collapse;\n"
832 "table.apg-state th:nth-last-child(2),\n"
833 "table.apg-state td:nth-last-child(2) {\n"
834 " text-align: right;\n"
836 "table.apg-state caption {\n"
837 " font-size: 125%;\n"
838 " line-height: 130%;\n"
839 " font-weight: bold;\n"
840 " text-align: left;\n"
842 "table.apg-stats {\n"
843 " font-family: monospace;\n"
844 " margin-top: 5px;\n"
845 " font-size: 11px;\n"
846 " line-height: 130%;\n"
847 " text-align: right;\n"
848 " border: 1px solid black;\n"
849 " border-collapse: collapse;\n"
851 "table.apg-stats th,\n"
852 "table.apg-stats td {\n"
853 " text-align: right;\n"
854 " border: 1px solid black;\n"
855 " border-collapse: collapse;\n"
857 "table.apg-stats caption {\n"
858 " font-size: 125%;\n"
859 " line-height: 130%;\n"
860 " font-weight: bold;\n"
861 " text-align: left;\n"
863 "table.apg-trace {\n"
864 " font-family: monospace;\n"
865 " margin-top: 5px;\n"
866 " font-size: 11px;\n"
867 " line-height: 130%;\n"
868 " text-align: right;\n"
869 " border: 1px solid black;\n"
870 " border-collapse: collapse;\n"
872 "table.apg-trace caption {\n"
873 " font-size: 125%;\n"
874 " line-height: 130%;\n"
875 " font-weight: bold;\n"
876 " text-align: left;\n"
878 "table.apg-trace th,\n"
879 "table.apg-trace td {\n"
880 " text-align: right;\n"
881 " border: 1px solid black;\n"
882 " border-collapse: collapse;\n"
884 "table.apg-trace th:last-child,\n"
885 "table.apg-trace th:nth-last-child(2),\n"
886 "table.apg-trace td:last-child,\n"
887 "table.apg-trace td:nth-last-child(2) {\n"
888 " text-align: left;\n"
890 "table.apg-grammar {\n"
891 " font-family: monospace;\n"
892 " margin-top: 5px;\n"
893 " font-size: 11px;\n"
894 " line-height: 130%;\n"
895 " text-align: right;\n"
896 " border: 1px solid black;\n"
897 " border-collapse: collapse;\n"
899 "table.apg-grammar caption {\n"
900 " font-size: 125%;\n"
901 " line-height: 130%;\n"
902 " font-weight: bold;\n"
903 " text-align: left;\n"
905 "table.apg-grammar th,\n"
906 "table.apg-grammar td {\n"
907 " text-align: right;\n"
908 " border: 1px solid black;\n"
909 " border-collapse: collapse;\n"
911 "table.apg-grammar th:last-child,\n"
912 "table.apg-grammar td:last-child {\n"
913 " text-align: left;\n"
915 "table.apg-rules {\n"
916 " font-family: monospace;\n"
917 " margin-top: 5px;\n"
918 " font-size: 11px;\n"
919 " line-height: 130%;\n"
920 " text-align: right;\n"
921 " border: 1px solid black;\n"
922 " border-collapse: collapse;\n"
924 "table.apg-rules caption {\n"
925 " font-size: 125%;\n"
926 " line-height: 130%;\n"
927 " font-weight: bold;\n"
928 " text-align: left;\n"
930 "table.apg-rules th,\n"
931 "table.apg-rules td {\n"
932 " text-align: right;\n"
933 " border: 1px solid black;\n"
934 " border-collapse: collapse;\n"
936 "table.apg-rules a {\n"
937 " color: #003399 !important;\n"
939 "table.apg-rules a:hover {\n"
940 " color: #8caae6 !important;\n"
942 "table.apg-attrs {\n"
943 " font-family: monospace;\n"
944 " margin-top: 5px;\n"
945 " font-size: 11px;\n"
946 " line-height: 130%;\n"
947 " text-align: center;\n"
948 " border: 1px solid black;\n"
949 " border-collapse: collapse;\n"
951 "table.apg-attrs caption {\n"
952 " font-size: 125%;\n"
953 " line-height: 130%;\n"
954 " font-weight: bold;\n"
955 " text-align: left;\n"
957 "table.apg-attrs th,\n"
958 "table.apg-attrs td {\n"
959 " text-align: center;\n"
960 " border: 1px solid black;\n"
961 " border-collapse: collapse;\n"
963 "table.apg-attrs th:nth-child(1),\n"
964 "table.apg-attrs th:nth-child(2),\n"
965 "table.apg-attrs th:nth-child(3) {\n"
966 " text-align: right;\n"
968 "table.apg-attrs td:nth-child(1),\n"
969 "table.apg-attrs td:nth-child(2),\n"
970 "table.apg-attrs td:nth-child(3) {\n"
971 " text-align: right;\n"
973 "table.apg-attrs a {\n"
974 " color: #003399 !important;\n"
976 "table.apg-attrs a:hover {\n"
977 " color: #8caae6 !important;\n"
982 static const char* s_cpHtmlFooter =
983 "<p class=\"apg-mono\">legend:<br>\n"
984 "(a) - this line number<br>\n"
985 "(b) - tree depth<br>\n"
986 "(c) - trace depth<br>\n"
987 "(d) - operator state<br>\n"
988 "(e) - phrase offset<br>\n"
989 "(f) - phrase length<br>\n"
990 " - <span class=\"apg-active\">↓</span> phrase opened<br>\n"
991 " - <span class=\"apg-match\">↑M</span> phrase matched<br>\n"
992 " - <span class=\"apg-empty\">↑E</span> phrase matched empty (phrase length = 0)<br>\n"
993 " - <span class=\"apg-nomatch\">↑N</span> phrase not matched<br>\n"
994 "operator - ALT, CAT, REP, RNM, TRG, TLS, TBS<sup>†</sup>, UDT, AND, NOT, BKA, BKN, BKR, ABG, AEN<sup>‡</sup><br>\n"
995 "phrase - up to 120 characters of the phrase being matched<br>\n"
996 " - <span class=\"apg-match\">matched characters</span><br>\n"
997 " - <span class=\"apg-lh-match\">matched characters in look ahead mode</span><br>\n"
998 " - <span class=\"apg-lb-match\">matched characters in look behind mode</span><br>\n"
999 " - <span class=\"apg-remainder\">remainder characters(not yet examined by parser)</span><br>\n"
1000 " - <span class=\"apg-ctrl-char\">control characters, TAB, LF, CR, etc. (ASCII mode only)</span><br>\n"
1001 " - <span class=\"apg-empty\">𝜺</span> empty string<br>\n"
1002 " - <span class=\"apg-line-end\">•</span> end of input string<br>\n"
1003 " - <span class=\"apg-line-end\">…</span> input string display truncated<br>\n"
1005 "<p class=\"apg-mono\">\n"
1006 "<sup>†</sup>original ABNF operators:<br>\n"
1007 "ALT - alternation<br>\n"
1008 "CAT - concatenation<br>\n"
1009 "REP - repetition<br>\n"
1010 "RNM - rule name<br>\n"
1011 "TRG - terminal range<br>\n"
1012 "TLS - terminal literal string (case insensitive)<br>\n"
1013 "TBS - terminal binary string (case sensitive)<br>\n"
1015 "<sup>‡</sup>super set SABNF operators:<br>\n"
1016 "UDT - user-defined terminal<br>\n"
1017 "AND - positive look ahead<br>\n"
1018 "NOT - negative look ahead<br>\n"
1019 "BKA - positive look behind<br>\n"
1020 "BKN - negative look behind<br>\n"
1021 "BKR - back reference<br>\n"
1022 "ABG - anchor - begin of input string<br>\n"
1023 "AEN - anchor - end of input string<br>\n"