Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
operators-sabnf.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 * *************************************************************************************/
37 #include "./apg.h"
38 #ifndef APG_STRICT_ABNF
39 #include "./lib.h"
40 #include "./parserp.h"
41 #include "./astp.h"
42 #include "./tracep.h"
43 #include "./statsp.h"
44 #include "./operators.h"
45 #include "./backref.h"
46 #include "./backrefu.h"
47 #include "./backrefp.h"
48 
49 void vUdt(parser* spCtx, const opcode* spOp) {
50  udt* spUdt = spOp->sUdt.spUdt;
51  parser_callback pfnCallback = spUdt->pfnCallback;
52  aint uiOffset = spCtx->uiOffset;
53  aint uiState;
54  spCtx->sState.uiHitCount++;
55  spCtx->uiTreeDepth++;
56  if(spCtx->uiTreeDepth > spCtx->sState.uiMaxTreeDepth){
57  spCtx->sState.uiMaxTreeDepth = spCtx->uiTreeDepth;
58  }
59  TRACE_DOWN(spCtx->vpTrace, spOp, spCtx->uiOffset);
60  AST_RULE_OPEN(spCtx->vpAst, spCtx->uiInLookaround, (spCtx->uiRuleCount + spUdt->uiUdtIndex), spCtx->uiOffset);
61 
62  // call the callback
63  spCtx->sCBData.uiCallbackState = ID_ACTIVE;
64  spCtx->sCBData.uiCallbackPhraseLength = 0;
65  spCtx->sCBData.uiParserOffset = uiOffset - spCtx->uiSubStringBeg;
66  spCtx->sCBData.uiParserState = ID_ACTIVE;
67  spCtx->sCBData.uiParserPhraseLength = 0;
68  spCtx->sCBData.uiRuleIndex = APG_UNDEFINED;
69  spCtx->sCBData.uiUDTIndex = spUdt->uiUdtIndex;
70  pfnCallback(&spCtx->sCBData);
71 
72  // validate the results
73  uiState = spCtx->sCBData.uiCallbackState;
74  if (uiState == ID_ACTIVE) {
75  XTHROW(spCtx->spException,
76  "user UDT callback function: returned invalid ID_ACTIVE state");
77  }
78  if (uiState == ID_EMPTY) {
79  // caller should not return ID_EMPTY but give her a break
80  spCtx->sCBData.uiCallbackState = ID_MATCH;
81  spCtx->sCBData.uiCallbackPhraseLength = 0;
82  }
83  // validate the phrase length & state
84  if ((uiOffset + spCtx->sCBData.uiCallbackPhraseLength) > spCtx->uiSubStringEnd) {
85  XTHROW(spCtx->spException,
86  "user UDT callback function: returned phrase length too long - beyond end of input string");
87  }
88  if ((spUdt->uiEmpty == APG_FALSE) && (spCtx->sCBData.uiCallbackState == ID_MATCH)
89  && (spCtx->sCBData.uiCallbackPhraseLength == 0)) {
90  XTHROW(spCtx->spException,
91  "user UDT callback function: returned empty phrase for non-empty UDT");
92  }
93 
94  // accept the results
95  spCtx->uiOpState = spCtx->sCBData.uiCallbackState;
96  spCtx->uiOffset = uiOffset + spCtx->sCBData.uiCallbackPhraseLength;
97  spCtx->uiPhraseLength = spCtx->sCBData.uiCallbackPhraseLength;
98  BKRU_UDT_CLOSE(spCtx->vpBkru, spUdt->uiUdtIndex, spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
99  BKRP_UDT_CLOSE(spCtx->vpBkrp, spUdt->uiUdtIndex, spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
100  AST_RULE_CLOSE(spCtx->vpAst, spCtx->uiInLookaround, (spCtx->uiRuleCount + spUdt->uiUdtIndex), spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
101  TRACE_UP(spCtx->vpTrace, spOp, spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
102  STATS_HIT(spCtx->vpStats, spOp, spCtx->uiOpState);
103  spCtx->uiTreeDepth--;
104 }
105 
106 void vAnd(parser* spCtx, const opcode* spOp) {
107  aint uiOffset = spCtx->uiOffset;
108  spCtx->sState.uiHitCount++;
109  spCtx->uiTreeDepth++;
110  if(spCtx->uiTreeDepth > spCtx->sState.uiMaxTreeDepth){
111  spCtx->sState.uiMaxTreeDepth = spCtx->uiTreeDepth;
112  }
113  TRACE_DOWN(spCtx->vpTrace, spOp, spCtx->uiOffset);
114  AST_OP_OPEN(spCtx->vpAst, spCtx->uiInLookaround);
115  PPPT_OPEN(spCtx, spOp, spCtx->uiOffset);
116  spCtx->uiInLookaround++;
117  spCtx->pfnOpFunc[(spOp + 1)->sGen.uiId](spCtx, (spOp + 1));
118 
119  // if child returns ID_MATCH or ID_NOMATCH, AND returns ID_MATCH or ID_NOMATCH, respectively
120  spCtx->uiOffset = uiOffset;
121  spCtx->uiPhraseLength = 0;
122  spCtx->uiInLookaround--;
123  PPPT_CLOSE;
124  AST_OP_CLOSE(spCtx->vpAst, spCtx->uiInLookaround, spCtx->uiOpState);
125  TRACE_UP(spCtx->vpTrace, spOp, spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
126  STATS_HIT(spCtx->vpStats, spOp, spCtx->uiOpState);
127  spCtx->uiTreeDepth--;
128 }
129 
130 void vNot(parser* spCtx, const opcode* spOp) {
131  aint uiOffset = spCtx->uiOffset;
132  spCtx->sState.uiHitCount++;
133  spCtx->uiTreeDepth++;
134  if(spCtx->uiTreeDepth > spCtx->sState.uiMaxTreeDepth){
135  spCtx->sState.uiMaxTreeDepth = spCtx->uiTreeDepth;
136  }
137  TRACE_DOWN(spCtx->vpTrace, spOp, spCtx->uiOffset);
138  AST_OP_OPEN(spCtx->vpAst, spCtx->uiInLookaround);
139  PPPT_OPEN(spCtx, spOp, spCtx->uiOffset);
140  spCtx->uiInLookaround++;
141  spCtx->pfnOpFunc[(spOp + 1)->sGen.uiId](spCtx, (spOp + 1));
142 
143  // if child returns ID_MATCH or ID_NOMATCH, NOT returns ID_NOMATCH or ID_MATCH, respectively
144  spCtx->uiOpState = spCtx->uiOpState == ID_MATCH ? ID_NOMATCH : ID_MATCH;
145  spCtx->uiOffset = uiOffset;
146  spCtx->uiPhraseLength = 0;
147  spCtx->uiInLookaround--;
148  PPPT_CLOSE;
149  AST_OP_CLOSE(spCtx->vpAst, spCtx->uiInLookaround, spCtx->uiOpState);
150  TRACE_UP(spCtx->vpTrace, spOp, spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
151  STATS_HIT(spCtx->vpStats, spOp, spCtx->uiOpState);
152  spCtx->uiTreeDepth--;
153 }
154 
155 static void vLookBack(parser* spCtx, const opcode* spOp) {
156  aint uiOffset = spCtx->uiOffset;
157  aint uiSubStringBeg = spCtx->uiSubStringBeg;
158  aint uiSubStringEnd = spCtx->uiSubStringEnd;
159  aint uiLen = uiOffset < spCtx->uiLookBehindLength ? uiOffset : spCtx->uiLookBehindLength;
160  aint ui = 0;
161  spCtx->uiSubStringBeg = uiOffset;
162  spCtx->uiSubStringEnd = uiOffset;
163  for (; ui <= uiLen; ui += 1) {
164  spCtx->uiOffset = uiOffset - ui;
165  spCtx->pfnOpFunc[spOp->sGen.uiId](spCtx, spOp);
166  if (spCtx->uiOpState == ID_MATCH) {
167  if(spCtx->uiPhraseLength != ui){
168  spCtx->uiOpState = ID_NOMATCH;
169  }
170  break;
171  }
172  }
173  spCtx->uiOffset = uiOffset;
174  spCtx->uiPhraseLength = 0;
175  spCtx->uiSubStringBeg = uiSubStringBeg;
176  spCtx->uiSubStringEnd = uiSubStringEnd;
177  spCtx->uiTreeDepth--;
178 }
179 
189 void vBka(parser* spCtx, const opcode* spOp) {
190  spCtx->sState.uiHitCount++;
191  spCtx->uiTreeDepth++;
192  if(spCtx->uiTreeDepth > spCtx->sState.uiMaxTreeDepth){
193  spCtx->sState.uiMaxTreeDepth = spCtx->uiTreeDepth;
194  }
195  TRACE_DOWN(spCtx->vpTrace, spOp, spCtx->uiOffset);
196  AST_OP_OPEN(spCtx->vpAst, spCtx->uiInLookaround);
197  spCtx->uiInLookaround++;
198  vLookBack(spCtx, (spOp + 1));
199  spCtx->uiInLookaround--;
200  AST_OP_CLOSE(spCtx->vpAst, spCtx->uiInLookaround, spCtx->uiOpState);
201  TRACE_UP(spCtx->vpTrace, spOp, spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
202  STATS_HIT(spCtx->vpStats, spOp, spCtx->uiOpState);
203  spCtx->uiTreeDepth--;
204 }
205 
215 void vBkn(parser* spCtx, const opcode* spOp) {
216  spCtx->sState.uiHitCount++;
217  spCtx->uiTreeDepth++;
218  if(spCtx->uiTreeDepth > spCtx->sState.uiMaxTreeDepth){
219  spCtx->sState.uiMaxTreeDepth = spCtx->uiTreeDepth;
220  }
221  TRACE_DOWN(spCtx->vpTrace, spOp, spCtx->uiOffset);
222  AST_OP_OPEN(spCtx->vpAst, spCtx->uiInLookaround);
223  spCtx->uiInLookaround++;
224  vLookBack(spCtx, (spOp + 1));
225  spCtx->uiOpState = (spCtx->uiOpState == ID_MATCH) ? ID_NOMATCH : ID_MATCH;
226  spCtx->uiInLookaround--;
227  AST_OP_CLOSE(spCtx->vpAst, spCtx->uiInLookaround, spCtx->uiOpState);
228  TRACE_UP(spCtx->vpTrace, spOp, spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
229  STATS_HIT(spCtx->vpStats, spOp, spCtx->uiOpState);
230  spCtx->uiTreeDepth--;
231 }
232 
233 void vAbg(parser* spCtx, const opcode* spOp) {
234  spCtx->sState.uiHitCount++;
235  spCtx->uiTreeDepth++;
236  if(spCtx->uiTreeDepth > spCtx->sState.uiMaxTreeDepth){
237  spCtx->sState.uiMaxTreeDepth = spCtx->uiTreeDepth;
238  }
239  TRACE_DOWN(spCtx->vpTrace, spOp, spCtx->uiOffset);
240 
241  // offset must match the beginning of the full input string (not just the sub-string)
242  spCtx->uiOpState = (spCtx->uiOffset == 0) ? ID_MATCH : ID_NOMATCH;
243  spCtx->uiPhraseLength = 0;
244  TRACE_UP(spCtx->vpTrace, spOp, spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
245  STATS_HIT(spCtx->vpStats, spOp, spCtx->uiOpState);
246  spCtx->uiTreeDepth--;
247 }
248 
249 void vAen(parser* spCtx, const opcode* spOp) {
250  spCtx->sState.uiHitCount++;
251  spCtx->uiTreeDepth++;
252  if(spCtx->uiTreeDepth > spCtx->sState.uiMaxTreeDepth){
253  spCtx->sState.uiMaxTreeDepth = spCtx->uiTreeDepth;
254  }
255  TRACE_DOWN(spCtx->vpTrace, spOp, spCtx->uiOffset);
256 
257  // offset must match the end of the full input string (not just the sub-string)
258  spCtx->uiOpState = (spCtx->uiOffset == spCtx->uiInputStringLength) ? ID_MATCH : ID_NOMATCH;
259  spCtx->uiPhraseLength = 0;
260  TRACE_UP(spCtx->vpTrace, spOp, spCtx->uiOpState, (spCtx->uiOffset - spCtx->uiPhraseLength), spCtx->uiPhraseLength);
261  STATS_HIT(spCtx->vpStats, spOp, spCtx->uiOpState);
262  spCtx->uiTreeDepth--;
263 }
264 
265 #endif /* APG_STRICT_ABNF */
lib.h
This header "#include"s all publid lib headers and other standard headers needed by most objects.
backrefp.h
The parent-mode back reference object.
apg.h
The APG header file.
vBka
void vBka(parser *spCtx, const opcode *spOp)
Definition: operators-sabnf.c:189
parserp.h
Private header for the SABNF parser.
udt::pfnCallback
parser_callback pfnCallback
Pointer to the call back function for this UDT. The parser will throw an exception if this is NULL....
Definition: parserp.h:135
AST_OP_OPEN
#define AST_OP_OPEN(x, l)
Definition: apg.h:255
vAbg
void vAbg(parser *spCtx, const opcode *spOp)
Definition: operators-sabnf.c:233
STATS_HIT
#define STATS_HIT(x, o, s)
Definition: apg.h:190
ID_EMPTY
#define ID_EMPTY
indicates a matched empty phrase parser state on return from parse tree below this node
Definition: parser.h:75
vAen
void vAen(parser *spCtx, const opcode *spOp)
Definition: operators-sabnf.c:249
XTHROW
#define XTHROW(ctx, msg)
Exception throw macro.
Definition: exception.h:67
parser_callback
void(* parser_callback)(callback_data *spData)
User-written callback function prototype.
Definition: parser.h:178
vBkn
void vBkn(parser *spCtx, const opcode *spOp)
Definition: operators-sabnf.c:215
aint
uint_fast32_t aint
The APG parser's unsigned integer type.
Definition: apg.h:79
backref.h
Private declarations common to both universal and parent modes.
AST_RULE_OPEN
#define AST_RULE_OPEN(x, l, i, o)
Definition: apg.h:253
BKRP_UDT_CLOSE
#define BKRP_UDT_CLOSE(x, i, s, o, p)
Definition: apg.h:223
ID_ACTIVE
#define ID_ACTIVE
indicates active parser state, parser has just entered the node and is moving down the parse tree
Definition: parser.h:72
vUdt
void vUdt(parser *spCtx, const opcode *spOp)
Definition: operators-sabnf.c:49
ID_MATCH
#define ID_MATCH
indicates a matched phrase parser state on return from parse tree below this node
Definition: parser.h:73
APG_UNDEFINED
#define APG_UNDEFINED
Definition: apg.h:318
udt::uiEmpty
aint uiEmpty
APG_TRUE if this UDT can be empty, APG_FALSE otherwise. Parser will throw an exception if this if fal...
Definition: parserp.h:137
AST_RULE_CLOSE
#define AST_RULE_CLOSE(x, l, i, s, o, p)
Definition: apg.h:254
AST_OP_CLOSE
#define AST_OP_CLOSE(x, l, s)
Definition: apg.h:256
tracep.h
Private header file for the trace functions.
vAnd
void vAnd(parser *spCtx, const opcode *spOp)
Definition: operators-sabnf.c:106
PPPT_OPEN
#define PPPT_OPEN(x, o, f)
Definition: apg.h:275
vNot
void vNot(parser *spCtx, const opcode *spOp)
Definition: operators-sabnf.c:130
ID_NOMATCH
#define ID_NOMATCH
indicates that no phrase was matched on return from parse tree below this node
Definition: parser.h:74
TRACE_DOWN
#define TRACE_DOWN(x, o, f)
Definition: apg.h:167
PPPT_CLOSE
#define PPPT_CLOSE
Definition: apg.h:276
astp.h
Private header file for the AST functions.
backrefu.h
The universal-mode back reference object.
operators.h
Header file for the suite of the parser's operator functions.
statsp.h
Private header file for the statistics gathering functions.
udt
Data structure for a single UDT.
Definition: parserp.h:133
TRACE_UP
#define TRACE_UP(x, o, s, f, p)
Definition: apg.h:168
udt::uiUdtIndex
aint uiUdtIndex
The UDT index - the zero-based order in which the UDT appears in the SABNF grammar.
Definition: parserp.h:139
APG_FALSE
#define APG_FALSE
Definition: apg.h:292
BKRU_UDT_CLOSE
#define BKRU_UDT_CLOSE(x, i, s, o, p)
Definition: apg.h:217
APG Version 7.0 is licensed under the 2-Clause BSD License,
an Open Source Initiative Approved License.