Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
rule-attributes.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 * *************************************************************************************/
43 #include "../api/api.h"
44 #include "../api/apip.h"
45 #include "../api/attributes.h"
46 
47 // when TRACE is defined, node information is printed for each node on the syntax tree of each rule
63 //#define TRACE_ATTRIBUTES 1
64 #ifdef TRACE_ATTRIBUTES
65 #include "./parserp.h"
66 #include "../utilities/utilities.h"
67 static aint s_uiTreeDepth = 0;
68 static void vRuleOpen(attrs_ctx* spAtt, const char* cpRuleName);
69 static void vRuleClose(attrs_ctx* spAtt, const char* cpRuleName, api_attr_w* spRuleAttr);
70 static void vOpcodeOpen(attrs_ctx* spAtt, api_op* spOp);
71 static void vOpcodeClose(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spOpAttr);
72 static void vIndent(aint uiIndent);
73 #define TRACE_RULE_OPEN(x,n) vRuleOpen((x), (n))
74 #define TRACE_RULE_CLOSE(x,n,a) vRuleClose((x), (n), (a))
75 #define TRACE_OPCODE_OPEN(x,o) vOpcodeOpen((x), (o))
76 #define TRACE_OPCODE_CLOSE(x,o,a) vOpcodeClose((x), (o), (a))
77 #define TRACE_OPCODE_CLOSE(x,o,a) vOpcodeClose((x), (o), (a))
78 #define TRACE_PRINT_ATTRS(x,t) vPrintAttrs((x), (t))
79 #else
80 #define TRACE_RULE_OPEN(x,n)
81 #define TRACE_RULE_CLOSE(x,n,a)
82 #define TRACE_OPCODE_OPEN(x,o)
83 #define TRACE_PRINT_ATTRS(x,t)
84 #define TRACE_OPCODE_CLOSE(x,o,a)
85 #endif /* TRACE_ATTRIBUTES */
86 
87 static void vAttrsInit(api_attr_w* spAttrs);
88 static void vRuleAttrs(attrs_ctx* spAtt, aint uiRuleIndex, api_attr_w* spAttrs);
89 static void vBkrAttrs(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spAttrs);
90 static void vOpcodeAttrs(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spAttrs);
91 static void vAltAttrs(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spAttrs);
92 static void vCatAttrs(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spAttrs);
93 static abool bIsCatLeft(api_attr_w* spChild, aint uiCount);
94 static abool bIsCatNested(api_attr_w* spChild, aint uiCount);
95 static abool bIsCatRight(api_attr_w* spChild, aint uiCount);
96 static abool bIsCatEmpty(api_attr_w* spChild, aint uiCount);
97 static abool bIsCatFinite(api_attr_w* spChild, aint uiCount);
98 static abool bIsCatCyclic(api_attr_w* spChild, aint uiCount);
99 
113  aint ui, uj;
114  api_attr_w sAttr;
115  aint uiRuleCount = spAtt->spApi->uiRuleCount;
116  for(ui = 0; ui < uiRuleCount; ui++){
117  // initialize ALL working attributes for a fresh start on each rule
118  for(uj = 0; uj < uiRuleCount; uj++){
119  vAttrsInit(&spAtt->spWorkingAttrs[uj]);
120  }
121 
122  // compute the attributes for this rule
123  spAtt->uiStartRule = ui;
124  vRuleAttrs(spAtt, ui, &sAttr);
125 
126  // save off the computed values in a permanent location
127  spAtt->spAttrs[ui] = spAtt->spWorkingAttrs[ui];
128  }
129 
130  // set the public attributes and check for errors
131  spAtt->uiErrorCount = 0;
132  api_attr* spPub = spAtt->spPublicAttrs;
133  api_attr* spErr = spAtt->spErrorAttrs;
134  api_attr_w* spWork = spAtt->spAttrs;
135  for(ui = 0; ui < uiRuleCount; ui++){
136  spPub->bCyclic = spWork->bCyclic;
137  spPub->bLeft = spWork->bLeft;
138  spPub->bRight = spWork->bRight;
139  spPub->bNested = spWork->bNested;
140  spPub->bFinite = spWork->bFinite;
141  spPub->bEmpty = spWork->bEmpty;
142  spPub->cpRuleName = spWork->cpRuleName;
143  spPub->uiRuleIndex = spWork->uiRuleIndex;
144  spPub->uiRecursiveType = spWork->uiRecursiveType;
145  spPub->uiMRGroup = spWork->uiMRGroup;
146  if(spPub->bLeft || spPub->bCyclic || !spPub->bFinite){
147  spErr->bCyclic = spWork->bCyclic;
148  spErr->bLeft = spWork->bLeft;
149  spErr->bRight = spWork->bRight;
150  spErr->bNested = spWork->bNested;
151  spErr->bFinite = spWork->bFinite;
152  spErr->bEmpty = spWork->bEmpty;
153  spErr->cpRuleName = spWork->cpRuleName;
154  spErr->uiRuleIndex = spWork->uiRuleIndex;
155  spErr->uiRecursiveType = spWork->uiRecursiveType;
156  spErr->uiMRGroup = spWork->uiMRGroup;
157  spErr++;
158  spAtt->uiErrorCount++;
159  }
160  spPub++;
161  spWork++;
162  }
163 }
164 
165 static void vAttrsInit(api_attr_w* spAttrs){
166  spAttrs->bLeft = APG_FALSE;
167  spAttrs->bNested = APG_FALSE;
168  spAttrs->bRight = APG_FALSE;
169  spAttrs->bCyclic = APG_FALSE;
170  spAttrs->bEmpty = APG_FALSE;
171  spAttrs->bFinite = APG_FALSE;
172  spAttrs->bLeaf = APG_FALSE;
173  spAttrs->bIsOpen = APG_FALSE;
174  spAttrs->bIsComplete = APG_FALSE;
175 }
176 
177 static void vRuleAttrs(attrs_ctx* spAtt, aint uiRuleIndex, api_attr_w* spAttrs) {
178  api_attr_w* spRuleAttrs;
179  api_op* spOp;
180 
181  TRACE_RULE_OPEN(spAtt, spAtt->spWorkingAttrs[uiRuleIndex].cpRuleName);
182  spRuleAttrs = &spAtt->spWorkingAttrs[uiRuleIndex];
183  if (spRuleAttrs->bIsComplete) {
184  // use final attributes
185  *spAttrs = *spRuleAttrs;
186  }else if (!spRuleAttrs->bIsOpen) {
187  // open the rule and traverse it
188  spRuleAttrs->bIsOpen = APG_TRUE;
189  spOp = &spAtt->spApi->spOpcodes[spAtt->spApi->spRules[uiRuleIndex].uiOpOffset];
190  vOpcodeAttrs(spAtt, spOp, spAttrs);
191 
192  // complete this rule's attributes
193  spRuleAttrs->bLeft = spAttrs->bLeft;
194  spRuleAttrs->bNested = spAttrs->bNested;
195  spRuleAttrs->bRight = spAttrs->bRight;
196  spRuleAttrs->bEmpty = spAttrs->bEmpty;
197  spRuleAttrs->bFinite = spAttrs->bFinite;
198  spRuleAttrs->bCyclic = spAttrs->bCyclic;
199  spRuleAttrs->bIsOpen = APG_FALSE;
200  spRuleAttrs->bIsComplete = APG_TRUE;
201  }else if(uiRuleIndex == spAtt->uiStartRule){
202  // use recursive leaf values
203  spAttrs->bLeft = APG_TRUE;
204  spAttrs->bRight = APG_TRUE;
205  spAttrs->bCyclic = APG_TRUE;
206  spAttrs->bLeaf = APG_TRUE;
207  }else{
208  // handle non-start rule terminal leaf
209  spAttrs->bFinite = APG_TRUE;
210  }
211  TRACE_RULE_CLOSE(spAtt, spRuleAttrs->cpRuleName, spAttrs);
212 }
213 
214 static void vOpcodeAttrs(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spAttrs) {
215  TRACE_OPCODE_OPEN(spAtt, spOp);
216  vAttrsInit(spAttrs);
217  switch (spOp->uiId) {
218  case ID_ALT:
219  vAltAttrs(spAtt, spOp, spAttrs);
220  break;
221  case ID_CAT:
222  vCatAttrs(spAtt, spOp, spAttrs);
223  break;
224  case ID_REP:
225  vOpcodeAttrs(spAtt, (spOp + 1), spAttrs);
226  if(spOp->luiMin == 0){
227  spAttrs->bEmpty = APG_TRUE;
228  spAttrs->bFinite = APG_TRUE;
229  }
230  break;
231  case ID_RNM:
232  vRuleAttrs(spAtt, spOp->uiIndex, spAttrs);
233  break;
234  case ID_BKR:
235  vBkrAttrs(spAtt, spOp, spAttrs);
236  break;
237  case ID_NOT:
238  case ID_AND:
239  case ID_BKA:
240  case ID_BKN:
241  vOpcodeAttrs(spAtt, (spOp + 1), spAttrs);
242  spAttrs->bEmpty = APG_TRUE;
243  break;
244  case ID_TLS:
245  spAttrs->bEmpty = spOp->uiAcharLength ? APG_FALSE : APG_TRUE;
246  spAttrs->bFinite = APG_TRUE;
247 // spAttrs->bCyclic = APG_FALSE;
248  break;
249  case ID_TRG:
250  case ID_TBS:
251  spAttrs->bEmpty = APG_FALSE;
252  spAttrs->bFinite = APG_TRUE;
253 // spAttrs->bCyclic = APG_FALSE;
254  break;
255  case ID_UDT:
256  spAttrs->bEmpty = spOp->uiEmpty ? APG_TRUE : APG_FALSE;
257  spAttrs->bFinite = APG_TRUE;
258  spAttrs->bCyclic = APG_FALSE;
259  break;
260  case ID_ABG:
261  case ID_AEN:
262  spAttrs->bEmpty = APG_TRUE;
263  spAttrs->bFinite = APG_TRUE;
264 // spAttrs->bCyclic = APG_FALSE;
265  break;
266  default:
267  XTHROW(spAtt->spException, "unknown opcode id encountered");
268  }
269  TRACE_OPCODE_CLOSE(spAtt, spOp, spAttrs);
270 }
271 
272 static void vAltAttrs(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spAttrs) {
273  aint ui;
274  aint uiCount = spOp->uiChildCount;
275  api_attr_w saChildren[uiCount];
276  api_op* spChildOp;
277  for (ui = 0; ui < uiCount; ui++) {
278  spChildOp = &spAtt->spApi->spOpcodes[spOp->uipChildIndex[ui]];
279  vOpcodeAttrs(spAtt, spChildOp, &saChildren[ui]);
280  }
281  // if any attribute is true for any ALT child, then it is true for the ALT node
282  spAttrs->bLeft = APG_FALSE;
283  spAttrs->bNested = APG_FALSE;
284  spAttrs->bRight = APG_FALSE;
285  spAttrs->bEmpty = APG_FALSE;
286  spAttrs->bFinite = APG_FALSE;
287  spAttrs->bCyclic = APG_FALSE;
288  for (ui = 0; ui < uiCount; ui++) {
289  if (saChildren[ui].bEmpty == APG_TRUE) {
290  spAttrs->bEmpty = APG_TRUE;
291  }
292  if (saChildren[ui].bFinite == APG_TRUE) {
293  spAttrs->bFinite = APG_TRUE;
294  }
295  if (saChildren[ui].bLeft == APG_TRUE) {
296  spAttrs->bLeft = APG_TRUE;
297  }
298  if (saChildren[ui].bNested == APG_TRUE) {
299  spAttrs->bNested = APG_TRUE;
300  }
301  if (saChildren[ui].bRight == APG_TRUE) {
302  spAttrs->bRight = APG_TRUE;
303  }
304  if (saChildren[ui].bCyclic == APG_TRUE) {
305  spAttrs->bCyclic = APG_TRUE;
306  }
307  }
308 }
309 static void vCatAttrs(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spAttrs) {
310  aint ui;
311  aint uiCount = spOp->uiChildCount;
312  api_attr_w saChildAttrs[uiCount];
313  api_op* spChildOp;
314  api_attr_w* spChild = &saChildAttrs[0];
315  for (ui = 0; ui < uiCount; ui++, spChild++) {
316  spChildOp = &spAtt->spApi->spOpcodes[spOp->uipChildIndex[ui]];
317  vOpcodeAttrs(spAtt, spChildOp, spChild);
318  }
319  spChild = &saChildAttrs[0];
320  spAttrs->bCyclic = bIsCatCyclic(spChild, uiCount);
321  spAttrs->bLeft = bIsCatLeft(spChild, uiCount);
322  spAttrs->bNested = bIsCatNested(spChild, uiCount);
323  spAttrs->bRight = bIsCatRight(spChild, uiCount);
324  spAttrs->bEmpty = bIsCatEmpty(spChild, uiCount);
325  spAttrs->bFinite = bIsCatFinite(spChild, uiCount);
326 }
327 static abool bIsCatCyclic(api_attr_w* spChild, aint uiCount){
328  // if all children are cyclic, CAT is cyclic (i.e. if any child is NOT cyclic, CAT is not cyclic)
329  abool bReturn = APG_TRUE;
330  aint ui = 0;
331  for (; ui < uiCount; ui++) {
332  if (spChild[ui].bCyclic == APG_FALSE) {
333  bReturn = APG_FALSE;
334  break;
335  }
336  }
337  return bReturn;
338 }
339 static abool bIsCatEmpty(api_attr_w* spChild, aint uiCount){
340  // if any child is not empty, CAT is not empty
341  abool bReturn = APG_TRUE;
342  aint ui = 0;
343  for (; ui < uiCount; ui++) {
344  if (spChild[ui].bEmpty != APG_TRUE) {
345  bReturn = APG_FALSE;
346  break;
347  }
348  }
349  return bReturn;
350 }
351 static abool bIsCatFinite(api_attr_w* spChild, aint uiCount){
352  // if any child is not finite, CAT is not finite
353  abool bReturn = APG_TRUE;
354  aint ui = 0;
355  for (; ui < uiCount; ui++) {
356  if (spChild[ui].bFinite != APG_TRUE) {
357  bReturn = APG_FALSE;
358  break;
359  }
360  }
361  return bReturn;
362 }
363 static abool bIsCatLeft(api_attr_w* spChild, aint uiCount) {
364  abool bReturn = APG_FALSE;
365  aint ui = 0;
366  for (; ui < uiCount; ui++) {
367  if (spChild[ui].bLeft == APG_TRUE) {
368  // if left-most, non-empty child is left, CAT is left
369  bReturn = APG_TRUE;
370  break;
371  } else if (!spChild[ui].bEmpty) {
372  // first non-empty child is not left or leaf, CAT is not left
373  bReturn = APG_FALSE;
374  break;
375  }// else keep looking
376  }
377  return bReturn;
378 }
379 static abool bIsCatRight(api_attr_w* spChild, aint uiCount) {
380  abool bReturn = APG_FALSE;
381  aint ui, uii;
382  for (ui = uiCount; ui > 0; ui--) {
383  uii = ui -1;
384  if (spChild[uii].bRight == APG_TRUE) {
385  // if right-most child is right, CAT is right
386  bReturn = APG_TRUE;
387  break;
388  } else if (!spChild[uii].bEmpty) {
389  // first non-empty child is not right or leaf, CAT is not right
390  bReturn = APG_FALSE;
391  break;
392  }// else keep looking
393  }
394  return bReturn;
395 }
396 static abool bEmptyOnly(api_attr_w* spAttr) {
397  if(spAttr->bLeft || spAttr->bNested ||spAttr->bRight || spAttr->bCyclic){
398  return APG_FALSE;
399  }
400  return spAttr->bEmpty;
401 }
402 static abool bIsRecursive(api_attr_w* spAttr) {
403  if(spAttr->bLeft || spAttr->bNested ||spAttr->bRight || spAttr->bCyclic){
404  return APG_TRUE;
405  }
406  return APG_FALSE;
407 }
408 static abool bIsCatNested(api_attr_w* spChild, aint uiCount) {
409  aint ui, uj, uk;
410  api_attr_w* spAi;
411  api_attr_w* spAj;
412  api_attr_w* spAk;
413  while (APG_TRUE) {
414  // 1.) if any child is nested, CAT is nested
415  for (ui = 0; ui < uiCount; ui++) {
416  spAi = &spChild[ui];
417  if (spAi->bNested == APG_TRUE) {
418  goto nested;
419  }
420  }
421 
422  // 2.) the left-most right recursive, non-leaf child is followed by at least one non-empty child
423  for (ui = 0; ui < uiCount; ui++) {
424  spAi = &spChild[ui];
425  if (spAi->bRight && !spAi->bLeaf) {
426  for (uj = ui + 1; uj < uiCount; uj++) {
427  spAj = &spChild[uj];
428  if (!bEmptyOnly(spAj)) {
429  goto nested;
430  }
431  }
432  }
433  }
434 
435  // 3.) the right-most left-recursive, non-leaf child is preceded by at least one non-empty child
436  for (ui = uiCount; ui > 0; ui--) {
437  spAi = &spChild[ui - 1];
438  if (spAi->bLeft && !spAi->bLeaf) {
439  for (uj = ui; uj > 0; uj--) {
440  spAj = &spChild[uj - 1];
441  if (!bEmptyOnly(spAj)) {
442  goto nested;
443  }
444  }
445  }
446  }
447 
448  // 4.) there is at least one recursive child between the left-most and right-most non-recursive children
449  for (ui = 0; ui < uiCount; ui++) {
450  spAi = &spChild[ui];
451  if (!spAi->bEmpty && !bIsRecursive(spAi)) {
452  for (uj = ui + 1; uj < uiCount; uj++) {
453  spAj = &spChild[uj];
454  if (bIsRecursive(spAj)) {
455  for (uk = uj + 1; uk < uiCount; uk++) {
456  spAk = &spChild[uk];
457  if (!spAk->bEmpty && !bIsRecursive(spAk)) {
458  goto nested;
459  }
460  }
461  }
462  }
463  }
464  }
465  break;
466  }
467  return APG_FALSE;
468  nested: return APG_TRUE;
469 }
470 
471 static void vBkrAttrs(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spAttrs) {
472  aint uiRuleCount = spAtt->spApi->uiRuleCount;
473  if (spOp->uiBkrIndex >= uiRuleCount) {
474  // use UDT values
475  spAttrs->bEmpty = spAtt->spApi->spUdts[spOp->uiBkrIndex - uiRuleCount].uiEmpty ? APG_TRUE : APG_FALSE;
476  spAttrs->bFinite = APG_TRUE;
477  } else {
478  // use the rule empty and finite values
479  vRuleAttrs(spAtt, spOp->uiBkrIndex, spAttrs);
480 
481  // however, this is a terminal node, like TLS except the string is not known in advance
482  spAttrs->bLeft = APG_FALSE;
483  spAttrs->bNested = APG_FALSE;
484  spAttrs->bRight = APG_FALSE;
485  spAttrs->bCyclic = APG_FALSE;
486  }
487 }
488 
489 #ifdef TRACE_ATTRIBUTES
490 static const char* s_cpTrue = "yes";
491 static const char* s_cpFalse = "no";
492 static const char* s_cpUndef = "undef";
493 static const char * cpBool(abool aTF) {
494  if (aTF == APG_TRUE) {
495  return s_cpTrue;
496  }
497  if (aTF == APG_FALSE) {
498  return s_cpFalse;
499  }
500  return s_cpUndef;
501 }
502 static void vRuleOpen(attrs_ctx* spAtt, const char* cpRuleName) {
503  vIndent(s_uiTreeDepth);
504  printf("%s: open\n", cpRuleName);
505  s_uiTreeDepth++;
506 }
507 static void vRuleClose(attrs_ctx* spAtt, const char* cpRuleName, api_attr_w* spRuleAttr) {
508  s_uiTreeDepth--;
509  vIndent(s_uiTreeDepth);
510  printf("%s: (l:%s, n:%s, r:%s, e:%s, f:%s, cyclic:%s)\n", cpRuleName,
511  cpBool(spRuleAttr->bLeft),cpBool(spRuleAttr->bNested), cpBool(spRuleAttr->bRight),
512  cpBool(spRuleAttr->bEmpty),cpBool(spRuleAttr->bFinite), cpBool(spRuleAttr->bCyclic));
513 }
514 static void vOpcodeOpen(attrs_ctx* spAtt, api_op* spOp) {
515  vIndent(s_uiTreeDepth);
516  printf("%s: open\n", cpUtilOpName(spOp->uiId));
517  s_uiTreeDepth++;
518 }
519 static void vOpcodeClose(attrs_ctx* spAtt, api_op* spOp, api_attr_w* spOpAttr) {
520  s_uiTreeDepth--;
521  vIndent(s_uiTreeDepth);
522  printf("%s: (l:%s, n:%s, r:%s, e:%s, f:%s, cyclic:%s)\n", cpUtilOpName(spOp->uiId),
523  cpBool(spOpAttr->bLeft),cpBool(spOpAttr->bNested), cpBool(spOpAttr->bRight),
524  cpBool(spOpAttr->bEmpty),cpBool(spOpAttr->bFinite), cpBool(spOpAttr->bCyclic));
525 }
526 static void vIndent(aint uiIndent) {
527  while (uiIndent--) {
528  printf(".");
529  }
530 }
531 #endif /* TRACE_ATTRIBUTES */
api_attr_w::bRight
abool bRight
APG_TRUE if the rule is right recursive.
Definition: apip.h:102
api_attr_w::bLeaf
abool bLeaf
APG_TRUE if this is a leaf rule (appears for a second time on a branch)
Definition: apip.h:106
api::spRules
api_rule * spRules
Points to an array of rule structures.
Definition: apip.h:145
ID_RNM
#define ID_RNM
rule name
Definition: parser.h:46
api_attr::bFinite
abool bFinite
APG_TRUE if the rule is finite.
Definition: api.h:72
api::spOpcodes
api_op * spOpcodes
Pointer to the array of opcodes for the SANF grammar.
Definition: apip.h:162
api_op::uiAcharLength
aint uiAcharLength
number of characters in TLS/TBS strings
Definition: apip.h:87
parserp.h
Private header for the SABNF parser.
attrs_ctx
The API will construct an attributes object. This is the attribute object's context.
Definition: attributes.h:41
TRACE_RULE_OPEN
#define TRACE_RULE_OPEN(x, n)
Definition: rule-attributes.c:80
api_attr_w
Working attribute information about a each rule.
Definition: apip.h:99
api_attr::bEmpty
abool bEmpty
APG_TRUE if the rule can be empty.
Definition: api.h:73
attrs_ctx::uiStartRule
aint uiStartRule
The grammar start rule.
Definition: attributes.h:51
ID_ALT
#define ID_ALT
alternation
Definition: parser.h:43
cpUtilOpName
const char * cpUtilOpName(aint uiId)
Convert an opcode identifier to a human-readable opcode name.
Definition: utilities.c:659
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
api_op::uiChildCount
aint uiChildCount
number of children for this ALT or CAT operator
Definition: apip.h:83
api_attr::uiMRGroup
aint uiMRGroup
the group number, if this is a member of a mutually-recursive group (there may be multiple groups)
Definition: api.h:77
api_attr::bNested
abool bNested
APG_TRUE if the rule is nested recursive.
Definition: api.h:69
api_attr
The recursive attributes of a single SABNF grammra rule.
Definition: api.h:67
api_attr_w::bLeft
abool bLeft
APG_TRUE if the rule is left recursive.
Definition: apip.h:100
ID_NOT
#define ID_NOT
negative look ahead
Definition: parser.h:57
ID_AND
#define ID_AND
positive look ahead
Definition: parser.h:56
api_attr_w::bFinite
abool bFinite
APG_TRUE if the rule is finite.
Definition: apip.h:104
api_attr::cpRuleName
const char * cpRuleName
the rule name for these attributes
Definition: api.h:74
api_attr_w::bIsComplete
abool bIsComplete
admin
Definition: apip.h:117
XTHROW
#define XTHROW(ctx, msg)
Exception throw macro.
Definition: exception.h:67
api_op::luiMin
luint luiMin
minimum value for REP and TRG opcodes
Definition: apip.h:84
api::spUdts
api_udt * spUdts
Points to an array of UDT structures, if one or more UDTs are referenced in the SABNF grammar.
Definition: apip.h:147
api::uiRuleCount
aint uiRuleCount
The number of rules in the SABNF grammar and in the array.
Definition: apip.h:146
aint
uint_fast32_t aint
The APG parser's unsigned integer type.
Definition: apg.h:79
ID_CAT
#define ID_CAT
concatenation
Definition: parser.h:44
ID_TRG
#define ID_TRG
terminal range
Definition: parser.h:47
ID_REP
#define ID_REP
repetition
Definition: parser.h:45
attrs_ctx::spErrorAttrs
api_attr * spErrorAttrs
An array of all rule attributes that have errors. (i.e. left recursive)
Definition: attributes.h:50
attrs_ctx::spApi
api * spApi
Pointer to the parent API context.
Definition: attributes.h:45
api_op::uiIndex
aint uiIndex
index of this referenced rule or UDT
Definition: apip.h:80
TRACE_OPCODE_OPEN
#define TRACE_OPCODE_OPEN(x, o)
Definition: rule-attributes.c:82
TRACE_OPCODE_CLOSE
#define TRACE_OPCODE_CLOSE(x, o, a)
Definition: rule-attributes.c:84
api_attr_w::uiRecursiveType
aint uiRecursiveType
ID_ATTR_N, ID_ATTR_R, ID_ATTR_MR, ID_ATTR_NMR, or ID_ATTR_RMR.
Definition: apip.h:109
api_attr::uiRecursiveType
aint uiRecursiveType
ID_ATTR_N, ID_ATTR_R, ID_ATTR_MR, ID_ATTR_NMR, or ID_ATTR_RMR.
Definition: api.h:76
api_attr_w::cpRuleName
char * cpRuleName
the rule name for these attributes
Definition: apip.h:107
TRACE_RULE_CLOSE
#define TRACE_RULE_CLOSE(x, n, a)
Definition: rule-attributes.c:81
api_op
API information about each opcode.
Definition: apip.h:78
ID_BKA
#define ID_BKA
positive look behind
Definition: parser.h:59
api_attr::bLeft
abool bLeft
APG_TRUE if the rule is left recursive.
Definition: api.h:68
api_attr::bRight
abool bRight
APG_TRUE if the rule is right recursive.
Definition: api.h:70
api_attr::bCyclic
abool bCyclic
APG_TRUE if the rule is cyclic.
Definition: api.h:71
attrs_ctx::spException
exception * spException
Pointer to the exception context inherited from the parent API.
Definition: attributes.h:43
api_op::uiId
aint uiId
type of opcode, ID_ALT, etc.
Definition: apip.h:79
ID_TLS
#define ID_TLS
terminal literal string
Definition: parser.h:49
APG_TRUE
#define APG_TRUE
Definition: apg.h:291
api_attr_w::bNested
abool bNested
APG_TRUE if the rule is nested recursive.
Definition: apip.h:101
api_op::uiEmpty
aint uiEmpty
APG_TRUE if this UDT can be empty, APG_FALSE otherwise
Definition: apip.h:81
attrs_ctx::spWorkingAttrs
api_attr_w * spWorkingAttrs
An array of private attribute structures.
Definition: attributes.h:46
api_attr_w::bIsOpen
abool bIsOpen
admin
Definition: apip.h:116
ID_BKN
#define ID_BKN
negative look behind
Definition: parser.h:60
abool
uint8_t abool
abool is the APG bool type.
Definition: apg.h:140
api_attr_w::bCyclic
abool bCyclic
APG_TRUE if the rule is cyclic.
Definition: apip.h:103
api_attr_w::uiRuleIndex
aint uiRuleIndex
the index of the rule for these attributes
Definition: apip.h:108
api_op::uiBkrIndex
aint uiBkrIndex
if BKR, this is the index to the rule or UDT that is being back referenced
Definition: apip.h:90
api_attr_w::uiMRGroup
aint uiMRGroup
the group number, if this is a member of a mutually-recursive group (there may be multiple groups)
Definition: apip.h:110
vRuleAttributes
void vRuleAttributes(attrs_ctx *spAtt)
Computes the attributes of each rule in the grammar.
Definition: rule-attributes.c:112
api_attr_w::bEmpty
abool bEmpty
APG_TRUE if the rule can be empty.
Definition: apip.h:105
api_op::uipChildIndex
aint * uipChildIndex
pointer to the first child index of this ALT or CAT operator
Definition: apip.h:82
attrs_ctx::spAttrs
api_attr_w * spAttrs
An array of private attribute structures used in their construction.
Definition: attributes.h:48
ID_ABG
#define ID_ABG
anchor - beginning of string
Definition: parser.h:61
api_rule::uiOpOffset
aint uiOpOffset
offset into the opcode table to the first opcode of this rule
Definition: apip.h:58
api_udt::uiEmpty
aint uiEmpty
APG_TRUE if this UDT can be empty, APG_FALSE otherwise
Definition: apip.h:72
ID_TBS
#define ID_TBS
terminal binary string
Definition: parser.h:48
api_attr::uiRuleIndex
aint uiRuleIndex
the index of the rule for these attributes
Definition: api.h:75
attrs_ctx::spPublicAttrs
api_attr * spPublicAttrs
When attributes a complete, the public version strips some of the unneeded variables used only in con...
Definition: attributes.h:49
attrs_ctx::uiErrorCount
aint uiErrorCount
The number of rules that have attribute errors.
Definition: attributes.h:52
ID_AEN
#define ID_AEN
anchor - end of string
Definition: parser.h:62
APG_FALSE
#define APG_FALSE
Definition: apg.h:292
APG Version 7.0 is licensed under the 2-Clause BSD License,
an Open Source Initiative Approved License.