Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
|
Go to the documentation of this file.
41 #include "../utilities/utilities.h"
47 static char* s_cpTrue =
"true";
48 static char* s_cpFalse =
"false";
50 static aint* uipUintValue(
char* cpValue,
aint* uipResult);
51 static abool* bpBoolValue(
char* cpValue,
abool* bpResult);
67 for (ui = 0; ui < spParser->uiRuleCount; ui++) {
71 if (spParser->uiUdtCount) {
72 for (ui = 0; ui < spParser->uiUdtCount; ui++) {
77 for (ui = 0; ui <
ID_GEN; ui++) {
96 char* cpFormat =
"trace output type %"PRIuMAX
" not recognized\n"
97 "must be TRACE_ASCII or TRACE_HTML";
107 snprintf(caBuf, 128, cpFormat, (
luint)uiType);
122 char* cpFormat =
"trace header type %"PRIuMAX
" not recognized\n"
123 "must be TRACE_HEADER_TRACE or TRACE_HEADER_APGEX";
132 snprintf(caBuf, 128, cpFormat, (
luint)uiType);
151 if(cpFileName[0] == 0){
167 char* cpDelim1 =
" =\t\n\r";
168 char* cpDelim2 =
" \t\n\r";
169 char* cpKey, *cpValue;
170 abool bValue, bEqual;
171 aint ui, uiKeyLen, uiLineLen, uiValue;
175 while(fgets(caLineBuf,
BUF_SIZE, spIn)){
176 if(caLineBuf[0] == 0x23){
179 if((caLineBuf[0] == 0x20) || (caLineBuf[0] == 0x09) || (caLineBuf[0] == 0x0A) || (caLineBuf[0] == 0x0D)){
184 strcpy(caLineSave, caLineBuf);
187 uiLineLen = (
aint)strlen(caLineBuf);
188 cpKey = strtok(caLineBuf, cpDelim1);
196 uiKeyLen = (
aint)strlen(cpKey);
198 for(ui = (uiKeyLen + 1); ui < uiLineLen; ui++){
199 if(caLineBuf[ui] == 0x3D){
203 if(((caLineBuf[ui] == 0x20) || (caLineBuf[ui] == 0x09))){
209 vMsgsLog(spCtx->
vpLog,
"key/value pair not separated with =");
214 cpValue = strtok(&caLineBuf[ui], cpDelim2);
222 if (strcmp(
"first-record", cpKey) == 0) {
223 if(!uipUintValue(cpValue, &uiValue)){
231 if (strcmp(
"max-records", cpKey) == 0) {
232 if(!uipUintValue(cpValue, &uiValue)){
246 if(!bpBoolValue(cpValue, &bValue)){
251 if (strcmp(
"all-rules", cpKey) == 0) {
253 for(ui = 0; ui < spCtx->
spParserCtx->uiRuleCount; ui++){
254 spConfig->
bpRules[ui] = bValue;
256 for(ui = 0; ui < spCtx->
spParserCtx->uiUdtCount; ui++){
257 spConfig->
bpUdts[ui] = bValue;
261 if (strcmp(
"all-ops", cpKey) == 0) {
263 for (ui = 0; ui <
ID_GEN; ui++) {
264 spConfig->
bpOps[ui] = bValue;
268 if (strcmp(
"count-only", cpKey) == 0) {
272 if (strcmp(
"PPPT", cpKey) == 0) {
280 if (strcmp(
"ALT", cpKey) == 0) {
284 if (strcmp(
"CAT", cpKey) == 0) {
288 if (strcmp(
"REP", cpKey) == 0) {
292 if (strcmp(
"TRG", cpKey) == 0) {
296 if (strcmp(
"TLS", cpKey) == 0) {
300 if (strcmp(
"TBS", cpKey) == 0) {
304 if (strcmp(
"BKR", cpKey) == 0) {
308 if (strcmp(
"AND", cpKey) == 0) {
312 if (strcmp(
"NOT", cpKey) == 0) {
316 if (strcmp(
"BKA", cpKey) == 0) {
320 if (strcmp(
"BKN", cpKey) == 0) {
324 if (strcmp(
"ABG", cpKey) == 0) {
328 if (strcmp(
"AEN", cpKey) == 0) {
332 if (strncmp(
"rule:", cpKey, 5) == 0) {
334 for (ui = 0; ui < spCtx->
spParserCtx->uiRuleCount; ui++, spRule++) {
340 snprintf(caBuf, (2*
BUF_SIZE),
"rule name \"%s\" not recognized", cpKey);
346 if (strncmp(
"UDT:", cpKey, 4) == 0) {
348 for (ui = 0; ui < spCtx->
spParserCtx->uiUdtCount; ui++, spUdt++) {
354 snprintf(caBuf, (2*
BUF_SIZE),
"UDT name \"%s\" not recognized", cpKey);
392 FILE* spOut = stdout;
396 spOut = fopen(cpFileName,
"wb");
401 fprintf(spOut,
"TRACE CONFIGURATION\n");
402 fprintf(spOut,
" %-15s: %s\n",
"all-rules", (spCfg->
bAllRules ? s_cpTrue : s_cpFalse));
403 fprintf(spOut,
" %-15s: %s\n",
"all-ops", (spCfg->
bAllOps ? s_cpTrue : s_cpFalse));
404 fprintf(spOut,
" %-15s: %s\n",
"count-only", (spCfg->
bCountOnly ? s_cpTrue : s_cpFalse));
405 fprintf(spOut,
" %-15s: %s\n",
"PPPT display", (spCfg->
bPppt ? s_cpTrue : s_cpFalse));
407 fprintf(spOut,
" %-15s: %"PRIuMAX
"\n",
"max-records", (
luint) spCfg->
uiMaxRecords);
408 fprintf(spOut,
"OPCODES\n");
409 fprintf(spOut,
" %-15s: %s\n",
"ALT", (spCfg->
bpOps[
ID_ALT] ? s_cpTrue : s_cpFalse));
410 fprintf(spOut,
" %-15s: %s\n",
"CAT", (spCfg->
bpOps[
ID_CAT] ? s_cpTrue : s_cpFalse));
411 fprintf(spOut,
" %-15s: %s\n",
"REP", (spCfg->
bpOps[
ID_REP] ? s_cpTrue : s_cpFalse));
412 fprintf(spOut,
" %-15s: %s\n",
"TRG", (spCfg->
bpOps[
ID_TRG] ? s_cpTrue : s_cpFalse));
413 fprintf(spOut,
" %-15s: %s\n",
"TBS", (spCfg->
bpOps[
ID_TBS] ? s_cpTrue : s_cpFalse));
414 fprintf(spOut,
" %-15s: %s\n",
"TLS", (spCfg->
bpOps[
ID_TLS] ? s_cpTrue : s_cpFalse));
415 fprintf(spOut,
" %-15s: %s\n",
"BKR", (spCfg->
bpOps[
ID_BKR] ? s_cpTrue : s_cpFalse));
416 fprintf(spOut,
" %-15s: %s\n",
"AND", (spCfg->
bpOps[
ID_AND] ? s_cpTrue : s_cpFalse));
417 fprintf(spOut,
" %-15s: %s\n",
"NOT", (spCfg->
bpOps[
ID_NOT] ? s_cpTrue : s_cpFalse));
418 fprintf(spOut,
" %-15s: %s\n",
"BKA", (spCfg->
bpOps[
ID_BKA] ? s_cpTrue : s_cpFalse));
419 fprintf(spOut,
" %-15s: %s\n",
"BKN", (spCfg->
bpOps[
ID_BKN] ? s_cpTrue : s_cpFalse));
420 fprintf(spOut,
" %-15s: %s\n",
"ABG", (spCfg->
bpOps[
ID_ABG] ? s_cpTrue : s_cpFalse));
421 fprintf(spOut,
" %-15s: %s\n",
"AEN", (spCfg->
bpOps[
ID_AEN] ? s_cpTrue : s_cpFalse));
422 fprintf(spOut,
"RULES\n");
424 for (ui = 0; ui < spCtx->
spParserCtx->uiRuleCount; ui++, spRule++) {
425 fprintf(spOut,
" %-15s: %s\n", spRule->
cpRuleName,
429 fprintf(spOut,
"UDTS\n");
431 for (ui = 0; ui < spCtx->
spParserCtx->uiUdtCount; ui++, spUdt++) {
432 fprintf(spOut,
" %-15s: %s\n", spUdt->
cpUdtName,
436 if (spOut != stdout) {
469 time_t tTime = time(NULL);
470 fprintf(spOut,
"# TRACE CONFIGURATION\n");
471 fprintf(spOut,
"# Generated by: %s\n", __func__);
472 fprintf(spOut,
"# %s", asctime(gmtime(&tTime)));
473 fprintf(spOut,
"#\n");
474 fprintf(spOut,
"# NOTE 1) All keys and values are case sensitive including the \"rule:\" and \"UDT:\" prefixes.\n");
475 fprintf(spOut,
"# However, rule and UDT names are case insensitive\n");
476 fprintf(spOut,
"# NOTE 2) true may be represented by true or t or 1\n");
477 fprintf(spOut,
"# false may be represented by false or f or 0\n");
478 fprintf(spOut,
"# NOTE 3) Lines beginning with # (0x23) or white space (0x09, 0x0A, 0x0D or 0x20) are ignored.\n");
479 fprintf(spOut,
"# NOTE 4) Missing keys assume the listed default values.\n");
480 fprintf(spOut,
"# NOTE 5) Unrecognized keys and values will result in error messages and a thrown exception.\n");
481 fprintf(spOut,
"#\n");
482 fprintf(spOut,
"# Sets all rule and UDT names to value. Default = true\n");
483 fprintf(spOut,
"all-rules = true\n");
484 fprintf(spOut,
"#\n");
485 fprintf(spOut,
"# Sets all opcodes to value. Default = true\n");
486 fprintf(spOut,
"all-ops = true\n");
487 fprintf(spOut,
"#\n");
488 fprintf(spOut,
"# If \"PPPT\" is true the Partially-Predictive Parsing Table (PPPT) form of output will be used.\n");
489 fprintf(spOut,
"# The PPPT form indicates when a predictive table value was used in place of an opcode.\n");
490 fprintf(spOut,
"# If no PPPT data is available \"PPPT\" is automatically set to false.\n");
491 fprintf(spOut,
"# \"PPPT\" defaults to true if PPPT data is available, false otherwise.\n");
492 fprintf(spOut,
"PPPT = true\n");
493 fprintf(spOut,
"#\n");
494 fprintf(spOut,
"# If \"count-only\" is true, only a count of the total number of records is displayed.\n");
495 fprintf(spOut,
"# The printing of individual records is suppressed.\n");
496 fprintf(spOut,
"# Handy for a first run on large grammars or input strings.\n");
497 fprintf(spOut,
"# It can help in setting the \"first-record\" and \"max-records\" parameters.\n");
498 fprintf(spOut,
"# Default = false\n");
499 fprintf(spOut,
"count-only = false\n");
500 fprintf(spOut,
"#\n");
501 fprintf(spOut,
"# \"first-record\" sets the record number of the first record to display.\n");
502 fprintf(spOut,
"# Records prior are not displayed. Default = 0.\n");
503 fprintf(spOut,
"first-record = 0\n");
504 fprintf(spOut,
"#\n");
505 fprintf(spOut,
"# \"max-records\" sets the maximum number of records to display.\n");
506 fprintf(spOut,
"# If 0, the maximum number of records is set to APG_MAX_AINT. Default = 0.\n");
507 fprintf(spOut,
"max-records = 0\n");
508 fprintf(spOut,
"#\n");
509 fprintf(spOut,
"# Set the opcodes to be displayed individually.\n");
510 fprintf(spOut,
"# They all default to the \"all-ops\" value.\n");
511 fprintf(spOut,
"# Un-comment and set the value if different from \"all-ops\".\n");
512 fprintf(spOut,
"# Note that depending on the SABNF grammar and input string,\n");
513 fprintf(spOut,
"# not all of these operators may generate trace records.\n");
514 fprintf(spOut,
"#ALT = true\n");
515 fprintf(spOut,
"#CAT = true\n");
516 fprintf(spOut,
"#REP = true\n");
517 fprintf(spOut,
"#TRG = true\n");
518 fprintf(spOut,
"#TBS = true\n");
519 fprintf(spOut,
"#TLS = true\n");
520 fprintf(spOut,
"#BKR = true\n");
521 fprintf(spOut,
"#AND = true\n");
522 fprintf(spOut,
"#NOT = true\n");
523 fprintf(spOut,
"#BKA = true\n");
524 fprintf(spOut,
"#BKN = true\n");
525 fprintf(spOut,
"#ABG = true\n");
526 fprintf(spOut,
"#AEN = true\n");
527 fprintf(spOut,
"#\n");
528 fprintf(spOut,
"# Set the rule & UDT names to be displayed individually.\n");
529 fprintf(spOut,
"# They all default to the \"all-rules\" value.\n");
530 fprintf(spOut,
"# Un-comment and set the value if different from \"all-rules\".\n");
531 fprintf(spOut,
"# Note that rule names must begin with \"rule:\" with no trailing spaces.\n");
532 fprintf(spOut,
"# and UDT names must begin with \"UDT:\" with no trailing spaces.\n");
534 for (ui = 0; ui < spCtx->
spParserCtx->uiRuleCount; ui++, spRule++) {
535 fprintf(spOut,
"#rule:%s = true\n", spRule->
cpRuleName);
538 fprintf(spOut,
"#\n");
540 for (ui = 0; ui < spCtx->
spParserCtx->uiUdtCount; ui++, spUdt++) {
541 fprintf(spOut,
"#UDT: %s = true\n", spUdt->
cpUdtName);
546 if (spOut != stdout) {
552 static abool* bpBoolValue(
char* cpValue,
abool* bpResult){
553 abool* bpReturn = NULL;
554 if(cpValue[0] == 116 || cpValue[0] == 49){
557 }
else if(cpValue[0] == 102 || cpValue[0] == 48){
563 static aint* uipUintValue(
char* cpValue,
aint* uipResult){
566 long int iLong = strtol(cpValue, &cpTailPtr, 10);
567 if(cpTailPtr == cpValue || errno != 0){
576 *uipResult = (
aint)iLong;
void vMsgsLog(void *vpCtx, const char *cpMsg)
Logs a message.
abool bAllRules
If true, all rule nodes will be displayed.
void vTraceConfigDisplay(void *vpCtx, const char *cpFileName)
Display the trace object's current configuration.
parser * spParserCtx
Pointer back to the parent parser's context.
Private header for the SABNF parser.
aint uiMsgsCount(void *vpCtx)
Get the number of logged messages.
Configuration defining the subset of nodes to display information for.
#define ID_ALT
alternation
#define ID_BKR
back reference to a previously matched rule or UDT name
void vUtilPrintMsgs(void *vpMsgs)
Display the list of messages in a message object to stdout.
FILE * spOpenFile
Pointer to any other open file.
void vExContext()
Handles bad context pointers.
abool bPppt
However, no records are actually displayed.
abool * bpUdts
An array of true/false indicators for each UDT in the SABNF grammar.
aint uiMaxRecords
Maximun number of records to display.
#define ID_NOT
negative look ahead
#define ID_AND
positive look ahead
abool * bpOps
An array of true/false indicators for each opcode in the SABNF grammar.
trace_config sConfig
Pointer to the trace configuration.
#define XTHROW(ctx, msg)
Exception throw macro.
aint uiRuleIndex
The rule index - zero-based order in which the rule appears in the SABNF grammar.
uint_fast32_t aint
The APG parser's unsigned integer type.
aint uiOutputType
Output type identifier (TRACE_ASCII or TRACE_HTML)
void * vpMsgsCtor(exception *spEx)
The Message Log constructor.
#define ID_CAT
concatenation
const char * cpUdtName
Pointer to the (null-terminated) ASCII rule name.
#define ID_TRG
terminal range
abool bAllOps
If true, all UDT nodes will be displayed.
void vMsgsDtor(void *vpCtx)
The object destructor.
uintmax_t luint
luint is used to cast integers suitable for the %"PRIuMAX" printf format.
#define ID_BKA
positive look behind
aint uiHeaderType
Indicates whether the trace is being done by apgex.
#define ID_GEN
general opcode (not SABNF). Serves to locate the ID in any opcode structure and must be larger than a...
void vTraceConfigGen(void *vpCtx, const char *cpFileName)
Generate a configuration file for the current parser.
#define TRACE_HEADER_APGEX
Identifies apgex as the header handler.
Private header file for the trace functions.
#define ID_TLS
terminal literal string
Data structure for a single rule.
void vTraceApgexType(void *vpCtx, aint uiType)
Called only by apgex. Sets the display type for apgex tracing.
#define TRACE_HTML
Identifier for HTML trace record format.
#define APG_MAX_AINT
Since the maximum unsigned integer value is used to indicate Infinite and Undefined values,...
#define ID_BKN
negative look behind
void vTraceConfig(void *vpCtx, const char *cpFileName)
Read a configuration file and set the trace configuration accordingly.
uint8_t abool
abool is the APG bool type.
abool * bpRules
An array of true/false indicators for each rule in the SABNF grammar.
#define TRACE_HEADER_TRACE
Identifies the trace object as the header handler.
#define TRACE_ASCII
Identifier for plain ASCII trace record format.
#define ID_ABG
anchor - beginning of string
The trace object context. Maintains the trace object's state.
aint uiFirstRecord
Number of the first record to display.
void vTraceOutputType(void *vpCtx, aint uiType)
Set the trace record display type.
#define ID_TBS
terminal binary string
abool bCountOnly
If true, trace will only count the number of records that would have been displayed.
abool bParserValidate(void *vpCtx)
Validate the context pointer of a parser.
Data structure for a single UDT.
void * vpLog
Pointer to a message log object for reporting configuration errors.
aint uiUdtIndex
The UDT index - the zero-based order in which the UDT appears in the SABNF grammar.
const char * cpRuleName
Pointer to the (null-terminated) ASCII rule name.
exception * spException
Pointer to the exception to use to report fatal errors back to the parser's catch block.
void vSetDefaultConfig(trace *spTrace)
Sets the default trace configuration on construction.
#define ID_AEN
anchor - end of string
APG Version 7.0 is licensed under the
2-Clause BSD License,
an Open Source Initiative Approved License.