Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
apgex.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 * *************************************************************************************/
38 #include "./apgex.h"
39 #include "../library/parserp.h"
40 #include "../library/tracep.h"
41 
43 #define BUF_SIZE (PATH_MAX + 256)
45 #define DOLLAR 36
46 #define AMP 38
47 #define ACCENT 96
48 #define APOS 39
49 #define LANGLE 60
50 #define RANGLE 62
51 #define UNDER 95
52 
57 typedef struct{
61 } phrase_r;
62 
68 typedef struct{
69  const char* cpRuleName;
73  aint uiLastPhrase;
75  abool bEnabled;
77 } rule_r;
78 
87 typedef struct{
88  const char* cpUdtName;
90  aint uiUdtIndex;
96 } udt_r;
97 
101 typedef struct{
107 } result_r;
108 
112 typedef struct{
113  const void* vpValidate;
115  void* vpMem;
117  void* vpVecSource;
119  void* vpVecPattern;
120  void* vpVecFlags;
121  void* vpVecRules;
122  void* vpVecUdts;
123  void* vpVecStrings;
124  void* vpVecPhrases;
127  void* vpVecRelUdts;
131  void* vpParser;
132  void* vpApi;
133  void* vpFmt;
134  void* vpAst;
135  void* vpTrace;
137  FILE* spDisplay;
157 } apgex;
158 
159 static const void* s_vpMagicNumber = (const void*)"apgex";
160 static const char* s_cpNoPattern = "No pattern or properties defined yet. This function call must be preceded by\n"
161  "vApgexPattern(), vApgexPatternFile() or vApgexPatternParser()";
162 static char s_cZero = 0;
163 static char* s_cpExternalPattern = "<external>";
164 static const char* s_cpEmptySource = "source cannot be NULL or empty";
165 static char* s_cpEndian = "???";
166 
167 static inline void vMakeAbsPhrase(apgex* spExp, phrase_r* spRelPhrase, apgex_phrase* spAbsPhrase);
168 static inline void vMakeRelPhrase(apgex* spExp, aint uiSourceOffset, aint uiLen, phrase_r* spPhrase);
169 static inline char* cpBool(abool bVal);
170 static void vClearForParse(apgex* spExp);
171 static void vClearForPattern(apgex* spExp);
172 static void vExecResult(apgex* spExp, apgex_result* spResult);
173 static abool bExecTest(apgex* spExp);
174 static void vMatchResult(apgex* spExp, parser_config* spConfig, parser_state* spState, apgex_result* spResult);
175 static void vMatchDefault(apgex* spExp, parser_config* spConfig, apgex_result* spResult);
176 static void vMatchGlobal(apgex* spExp, parser_config* spConfig, apgex_result* spResult);
177 static void vMatchSticky(apgex* spExp, parser_config* spConfig, apgex_result* spResult);
178 static abool bTestDefault(apgex* spExp, parser_config* spConfig);
179 static abool bTestGlobal(apgex* spExp, parser_config* spConfig);
180 static abool bTestSticky(apgex* spExp, parser_config* spConfig);
181 static void vReplacement(apgex* spExp, apgex_result* spResult);
182 static void vReplaceFunc(apgex* spExp, apgex_result* spResult, pfn_replace pfnFunc, void* vpUser);
183 static void vReplace(apgex* spExp, apgex_result* spResult);
184 static rule_r* spFindRule(apgex* spExp, const char* cpName);
185 static udt_r* spFindUdt(apgex* spExp, const char* cpName);
186 static aint pfnRuleCallback(ast_data* spData);
187 static aint pfnUdtCallback(ast_data* spData);
188 //static void pfnRuleCallback(callback_data* spData);
189 //static void pfnUdtCallback(callback_data* spData);
190 static void vPrintPhrase(apgex* spExp, apgex_phrase* spPhrase, FILE* spOut);
191 static void vDecodeFlags(apgex* spExp, const char* cpFlags);
192 static void vConstructParser(apgex* spExp);
193 static void vInitRules(apgex* spExp);
194 static void vInitCallbacks(apgex* spExp);
195 static void vResetCallbacks(apgex* spExp);
196 static abool bIsNameChar(char cChar);
197 static void vNamePhrase(apgex* spExp, achar* acpName, aint uiNameLen, apg_phrase* spPhrase);
198 
204 #ifdef APG_TRACE
206 #define TRACE_APGEX_HEADER(t) vTraceApgexHeader((t))
207 #define TRACE_APGEX_FOOTER(t) vTraceApgexFooter((t))
208 #define TRACE_APGEX_SEPARATOR(x) vTraceApgexSeparator((x)->vpTrace, (x)->uiLastIndex)
209 #define TRACE_APGEX_CHECK(x)
210 #define TRACE_APGEX_OUTPUT(x) vTraceApgexOutput((x))
211 static void vTraceApgexOutput(apgex *spExp) {
212  if (spExp->bTraceMode) {
213  spExp->vpTrace = vpTraceCtor(spExp->vpParser);
215  if (spExp->bTraceHtmlMode) {
217  }
218  }
219 }
220 #else
221 #define TRACE_APGEX_HEADER(t)
222 #define TRACE_APGEX_FOOTER(t)
223 #define TRACE_APGEX_SEPARATOR(x)
224 #define TRACE_APGEX_CHECK(x) vTraceApgexCheck((x))
225 #define TRACE_APGEX_OUTPUT(x)
226 static void vTraceApgexCheck(apgex* spExp){
227  if(spExp->bTraceMode){
228  XTHROW(spExp->spException, "to use the 't' or 'th' flag the application must be compiled with APG_TRACE defined");
229  }
230 }
231 #endif
232 
239 void* vpApgexCtor(exception* spEx){
240  if(!bExValidate(spEx)){
241  vExContext();
242  }
243  BKR_APGEX_CHECK(spEx);
244  void* vpMem = vpMemCtor(spEx);
245  apgex* spExp = (apgex*) vpMemAlloc(vpMem, sizeof(apgex));
246  memset((void*) spExp, 0, sizeof(apgex));
247  spExp->vpMem = vpMem;
248  spExp->spException = spEx;
249  spExp->vpApi = vpApiCtor(spExp->spException);
250  spExp->vpVecStrings = vpVecCtor(vpMem, sizeof(char), 1024);
251  spExp->vpVecSource = vpVecCtor(vpMem, sizeof(achar), 1024);
252  spExp->vpVecOriginalSource = vpVecCtor(vpMem, sizeof(achar), 16);
253  spExp->vpVecPattern = vpVecCtor(vpMem, sizeof(char), 4096);
254  spExp->vpVecFlags = vpVecCtor(vpMem, sizeof(char), 32);
255  spExp->vpVecRules = vpVecCtor(vpMem, sizeof(apgex_rule), 512);
256  spExp->vpVecUdts = vpVecCtor(vpMem, sizeof(apgex_rule), 64);
257  spExp->vpVecPhrases = vpVecCtor(vpMem, sizeof(apgex_phrase), 1024);
258  spExp->vpVecRelPhrases = vpVecCtor(vpMem, sizeof(phrase_r), 1024);
259  spExp->vpVecRelRules = vpVecCtor(vpMem, sizeof(rule_r), 512);
260  spExp->vpVecRelUdts = vpVecCtor(vpMem, sizeof(rule_r), 64);
261  spExp->vpVecReplaceRaw = vpVecCtor(vpMem, sizeof(achar), 1024);
262  spExp->vpVecReplacement = vpVecCtor(vpMem, sizeof(achar), 1024);
263  spExp->vpVecSplitPhrases = vpVecCtor(vpMem, sizeof(apg_phrase), 128);
264  spExp->vpFmt = vpFmtCtor(spEx);
265  spExp->bDefaultMode = APG_TRUE;
266  spExp->vpValidate = s_vpMagicNumber;
267  s_cpEndian = bIsBigEndian() ? "big" : "little";
268  return (void*) spExp;
269 }
270 
280  if(!bExValidate(spEx)){
281  vExContext();
282  }
283  XTHROW(spEx, "apgex must be compiled with the macro APG_BKR defined.");
284 }
285 
295 void vApgexDtor(void *vpCtx) {
296  if(vpCtx){
297  apgex* spExp = (apgex*) vpCtx;
298  if(spExp->vpValidate != s_vpMagicNumber){
299  vExContext(); // does not return
300  }
301  void* vpMem = spExp->vpMem;
302  if(!spExp->vpExternalParser){
303  // destroy the local parser, which destroys AST and trace object along with it
304  vParserDtor(spExp->vpParser);
305  }
306  if(spExp->spDisplay && (spExp->spDisplay != stdout)){
307  fclose(spExp->spDisplay);
308  spExp->spDisplay = NULL;
309  }
310  vApiDtor(spExp->vpApi);
311  vFmtDtor(spExp->vpFmt);
312  memset(vpCtx, 0, sizeof(apgex));
313  vMemDtor(vpMem);
314  }
315 }
316 
317 // /** \brief Validates an `apgex` context pointer.
318 // * \param vpCtx The pointer to validate.
319 // * \return Returns true if the pointer is valid, false otherwise.
320 // */
321 //abool bApgexValidate(void* vpCtx){
322 // apgex* spExp = (apgex*) vpCtx;
323 // if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
324 // return APG_FALSE;
325 // }
326 // return APG_TRUE;
327 //}
328 
378 void vApgexPattern(void* vpCtx, const char* cpPattern, const char* cpFlags){
379  apgex* spExp = (apgex*) vpCtx;
380  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
381  vExContext(); // does not return
382  }
383  vClearForPattern(spExp);
384  vDecodeFlags(spExp, cpFlags);
385 
386  // save a copy of the pattern & flags including the null terminator
387  vpVecPushn(spExp->vpVecPattern, (void*)cpPattern, (aint)(strlen(cpPattern) + 1));
388 
389  // construct the parser
390  vConstructParser(spExp);
391 
392  // initialize the rule list
393  vInitRules(spExp);
394 }
395 
404 void vApgexPatternFile(void* vpCtx, const char* cpFileName, const char* cpFlags){
405  apgex* spExp = (apgex*) vpCtx;
406  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
407  vExContext(); // does not return
408  }
409  if(!cpFileName || (strlen(cpFileName) == 0)){
410  XTHROW(spExp->spException, "cpFileName cannot be NULL or empty");
411  }
412  vClearForPattern(spExp);
413  vDecodeFlags(spExp, cpFlags);
414 
415  // get the pattern
416  aint uiSize = 1024;
417  aint uiPatternSize = uiSize;
418  vUtilFileRead(spExp->vpMem, cpFileName, NULL, &uiPatternSize);
419  uint8_t* ucpPattern = (uint8_t*)vpVecPushn(spExp->vpVecPattern, NULL, (uiPatternSize + 1));
420  vUtilFileRead(spExp->vpMem, cpFileName, ucpPattern, &uiPatternSize);
421  ucpPattern[uiPatternSize] = 0;
422 
423  // construct the parser
424  vConstructParser(spExp);
425 
426  // initialize the rule list
427  vInitRules(spExp);
428 }
429 
444 void vApgexPatternParser(void* vpCtx, void* vpParser, const char* cpFlags){
445  apgex* spExp = (apgex*) vpCtx;
446  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
447  vExContext(); // does not return
448  }
449  if(!vpParser){
450  XTHROW(spExp->spException, "vpParser cannot be NULL");
451  }
452  if(!bParserValidate(vpParser)){
453  XTHROW(spExp->spException, "vpParser is not a pointer to a valid parser object context");
454  }
455  vClearForPattern(spExp);
456  vDecodeFlags(spExp, cpFlags);
457 
458  // save an empty pattern
459  vpVecPushn(spExp->vpVecPattern, s_cpExternalPattern, (aint)(strlen(s_cpExternalPattern) + 1));
460 
461  // use the specified parser
462  spExp->vpExternalParser = vpParser;
463  spExp->vpParser = vpParser;
464  spExp->vpAst = vpAstCtor(spExp->vpParser);
465 
466  // initialize the rule list
467  vInitRules(spExp);
468 }
469 
479 apgex_result sApgexExec(void* vpCtx, apg_phrase* spSource){
480  apgex* spExp = (apgex*) vpCtx;
481  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
482  vExContext();
483  }
484  if(!spExp->vpParser){
485  XTHROW(spExp->spException, s_cpNoPattern);
486  }
487  if(!(spSource && spSource->acpPhrase && spSource->uiLength)){
488  XTHROW(spExp->spException, s_cpEmptySource);
489  }
490  apgex_result sResult = {};
491  vClearForParse(spExp);
492  vpVecPushn(spExp->vpVecSource, (void*)spSource->acpPhrase, spSource->uiLength);
493 
494  vInitCallbacks(spExp);
495  vExecResult(spExp, &sResult);
496  vResetCallbacks(spExp);
497  return sResult;
498 }
499 
528 apg_phrase sApgexReplace(void* vpCtx, apg_phrase* spSource, apg_phrase* spReplacement){
529  apgex* spExp = (apgex*) vpCtx;
530  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
531  vExContext();
532  }
533  if(!(spSource && spSource->acpPhrase && spSource->uiLength)){
534  XTHROW(spExp->spException, s_cpEmptySource);
535  }
536  apg_phrase sPhrase = {};
537  apgex_result sResult = {};
538  vClearForParse(spExp);
539  vInitCallbacks(spExp);
540  spExp->bReplaceMode = APG_TRUE;
541  vpVecPushn(spExp->vpVecSource, (void*)spSource->acpPhrase, spSource->uiLength);
542  vpVecPushn(spExp->vpVecOriginalSource, (void*)(void*)spSource->acpPhrase, spSource->uiLength);
543  if(spReplacement && spReplacement->acpPhrase && spReplacement->uiLength){
544  vpVecPushn(spExp->vpVecReplaceRaw, (void*)spReplacement->acpPhrase, spReplacement->uiLength);
545  }
546  if(spExp->bDefaultMode){
547  vExecResult(spExp, &sResult);
548  if(sResult.spResult){
549  vReplacement(spExp, &sResult);
550  vReplace(spExp, &sResult);
551  }
552  }else{
553  vExecResult(spExp, &sResult);
554  while(sResult.spResult){
555  vReplacement(spExp, &sResult);
556  vReplace(spExp, &sResult);
557  vExecResult(spExp, &sResult);
558  }
559  }
560  spExp->uiLastIndex = 0;
561  sPhrase.acpPhrase = (achar*)vpVecFirst(spExp->vpVecSource);
562  sPhrase.uiLength = uiVecLen(spExp->vpVecSource);
563  vResetCallbacks(spExp);
564  return sPhrase;
565 }
566 
581 apg_phrase sApgexReplaceFunc(void* vpCtx, apg_phrase* spSource, pfn_replace pfnFunc, void* vpUser){
582  apgex* spExp = (apgex*) vpCtx;
583  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
584  vExContext();
585  }
586  if(!(spSource && spSource->acpPhrase && spSource->uiLength)){
587  XTHROW(spExp->spException, s_cpEmptySource);
588  }
589  if(!pfnFunc){
590  XTHROW(spExp->spException, "pfnFunc cannot be NULL");
591  }
592  vClearForParse(spExp);
593  vInitCallbacks(spExp);
594  spExp->bReplaceMode = APG_TRUE;
595  vpVecPushn(spExp->vpVecSource, (void*)spSource->acpPhrase, spSource->uiLength);
596  vpVecPushn(spExp->vpVecOriginalSource, (void*)(void*)spSource->acpPhrase, spSource->uiLength);
597  apg_phrase sPhrase = {};
598  apgex_result sResult = {};
599  if(spExp->bDefaultMode){
600  vExecResult(spExp, &sResult);
601  if(sResult.spResult){
602  vReplaceFunc(spExp, &sResult, pfnFunc, vpUser);
603  vReplace(spExp, &sResult);
604  }
605  }else{
606  vExecResult(spExp, &sResult);
607  while(sResult.spResult){
608  vReplaceFunc(spExp, &sResult, pfnFunc, vpUser);
609  vReplace(spExp, &sResult);
610  vExecResult(spExp, &sResult);
611  }
612  }
613  spExp->uiLastIndex = 0;
614  sPhrase.acpPhrase = (achar*)vpVecFirst(spExp->vpVecSource);
615  sPhrase.uiLength = uiVecLen(spExp->vpVecSource);
616  vResetCallbacks(spExp);
617  return sPhrase;
618 }
619 
648 apg_phrase* spApgexSplit(void* vpCtx, apg_phrase* spSource, aint uiLimit, aint* uipCount){
649  apgex* spExp = (apgex*) vpCtx;
650  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
651  vExContext();
652  }
653  if(!(spSource && spSource->acpPhrase && spSource->uiLength)){
654  XTHROW(spExp->spException, s_cpEmptySource);
655  }
656  if(!uipCount){
657  XTHROW(spExp->spException, "the returned array count cannot be NULL");
658  }
659 
660  // ensure all UDTs are defined
661  aint ui;
662  for(ui = 0; ui < spExp->uiUdtCount; ui++){
663  if(!spExp->spRelUdts[ui].pfnUdt){
664  char caBuf[BUF_SIZE];
665  snprintf(caBuf, BUF_SIZE, "UDT \"%s\" not defined", spExp->spRelUdts[ui].cpUdtName);
666  XTHROW(spExp->spException, caBuf);
667  }
668  }
669  vClearForParse(spExp);
670  parser_config sConfig = {};
671  apgex_result sResult = {};
672  apg_phrase* spReturn = NULL;
673  apg_phrase sPhrase;
674  aint uiLen;
675  aint uiBegin = 0;
676  spExp->uiLastIndex = 0;
677  uiLimit = uiLimit ? uiLimit : APG_MAX_AINT;
678 
679  // save the source
680  vpVecPushn(spExp->vpVecSource, (void*)spSource->acpPhrase, spSource->uiLength);
681 
682  // disable all rules/UDTs
683  spExp->uiEnabledRuleCount = 0;
684  spExp->uiEnabledUdtCount = 0;
685  for(ui = 0; ui < spExp->uiRuleCount; ui++){
686  spExp->spRelRules[ui].bEnabled = APG_FALSE;
687  }
688  for(ui = 0; ui < spExp->uiUdtCount; ui++){
689  spExp->spRelUdts[ui].bEnabled = APG_FALSE;
690  }
691 
692  if(spExp->vpTrace){
693  // initalize the trace
694  TRACE_APGEX_HEADER(spExp->vpTrace);
695  }
696 
697  // initialize for the parser input
698  sConfig.acpInput = (achar*)vpVecFirst(spExp->vpVecSource);
699  sConfig.uiInputLength = uiVecLen(spExp->vpVecSource);
700  sConfig.bParseSubString = APG_TRUE;
701  sConfig.uiSubStringBeg = spExp->uiLastIndex;
702  sConfig.vpUserData = (void*)spExp;
703 
704  // look for phrase matches
705  sResult.spResult = (apgex_phrase*)1;
706  while(uiLimit && sResult.spResult){
707  sConfig.uiSubStringBeg = spExp->uiLastIndex;
708  uiBegin = spExp->uiLastIndex;
709  vMatchGlobal(spExp, &sConfig, &sResult);
710  if(sResult.spResult){
711  // push left context on the sub-phrase array
712  // make a phrase from the interval [uiBegin, uiLastIndex)
713  uiLen = sResult.spResult->sPhrase.uiLength ? sResult.spLeftContext->sPhrase.uiLength - uiBegin : 1;
714  if(uiLen){
715  sPhrase.acpPhrase = (achar*)vpVecFirst(spExp->vpVecSource) + uiBegin;
716  sPhrase.uiLength = uiLen;
717  vpVecPush(spExp->vpVecSplitPhrases, (void*)&sPhrase);
718  }
719  }else{
720  // push right context on the sub-phrase array
721  uiLen = sConfig.uiInputLength - uiBegin;
722  if(uiLen){
723  sPhrase.acpPhrase = (achar*)vpVecFirst(spExp->vpVecSource) + uiBegin;
724  sPhrase.uiLength = uiLen;
725  vpVecPush(spExp->vpVecSplitPhrases, (void*)&sPhrase);
726  }
727  }
728  uiLimit--;
729  }
730 
731  if(spExp->vpTrace){
732  // finalize the trace
733  TRACE_APGEX_FOOTER(spExp->vpTrace);
734  TRACE_DTOR(spExp->vpTrace);
735  spExp->vpTrace = NULL;
736  }
737  spReturn = (apg_phrase*)vpVecFirst(spExp->vpVecSplitPhrases);
738  *uipCount = uiVecLen(spExp->vpVecSplitPhrases);
739  vResetCallbacks(spExp);
740  return spReturn;
741 }
742 
752 abool bApgexTest(void* vpCtx, apg_phrase* spSource){
753  apgex* spExp = (apgex*) vpCtx;
754  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
755  vExContext();
756  }
757  if(!(spSource && spSource->acpPhrase && spSource->uiLength)){
758  XTHROW(spExp->spException, s_cpEmptySource);
759  }
760  vClearForParse(spExp);
761  vpVecPushn(spExp->vpVecSource, (void*)spSource->acpPhrase, spSource->uiLength);
762  return bExecTest(spExp);
763 }
764 
786 void vApgexEnableRules(void* vpCtx, const char* cpNames, abool bEnable){
787  apgex* spExp = (apgex*) vpCtx;
788  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
789  vExContext();
790  }
791  if(!spExp->vpParser){
792  XTHROW(spExp->spException, s_cpNoPattern);
793  }
794  if(!cpNames && !cpNames[0]){
795  XTHROW(spExp->spException, "names list, cpNames, cannot be NULL or empty");
796  }
797  aint uiStrLen = (aint)strlen(cpNames) + 1;
798  aint ui = 0;
799  aint uiNameLen = 0;
800  udt_r* spUdt;
801  rule_r* spRule;
802  char cChar;
803  char caBuf[BUF_SIZE];
804  bEnable = (bEnable > 0) ? APG_TRUE : APG_FALSE;
805  vVecClear(spExp->vpVecStrings);
806  char* cpNameBuf = (char*)vpVecPushn(spExp->vpVecStrings, NULL, (uiStrLen + 10));
807  for(; ui < uiStrLen; ui++){
808  cChar = cpNames[ui];
809  if(bIsNameChar(cChar)){
810  // create a new name
811  cpNameBuf[uiNameLen++] = cChar;
812  }else{
813  if(uiNameLen > 0){
814  // end a name
815  cpNameBuf[uiNameLen] = (char)0;
816  uiNameLen = 0;
817  if(iStriCmp(cpNameBuf, "--all") == 0){
818  goto all;
819  }
820 
821  // look up
822  spRule = spFindRule(spExp, cpNameBuf);
823  if(spRule){
824  spRule->bEnabled = bEnable;
825  }else{
826  spUdt = spFindUdt(spExp, cpNameBuf);
827  if(spUdt){
828  spUdt->bEnabled = bEnable;
829  }else{
830  snprintf(caBuf, BUF_SIZE, "\"%s\" is not a valid rule or UDT name", cpNameBuf);
831  vMemFree(spExp->vpMem, cpNameBuf);
832  XTHROW(spExp->spException, caBuf);
833  }
834  }
835  } // else ignore dilimiters
836  }
837  }
838  spExp->uiEnabledRuleCount = 0;
839  spExp->uiEnabledUdtCount = 0;
840  for(ui = 0; ui < spExp->uiRuleCount; ui++){
841  if(spExp->spRelRules[ui].bEnabled){
842  spExp->uiEnabledRuleCount++;
843  }
844  }
845  for(ui = 0; ui < spExp->uiUdtCount; ui++){
846  if(spExp->spRelUdts[ui].bEnabled){
847  spExp->uiEnabledUdtCount++;
848  }
849  }
850  return;
851  all:;
852  spExp->uiEnabledRuleCount = spExp->uiRuleCount;
853  spExp->uiEnabledUdtCount = spExp->uiUdtCount;
854  for(ui = 0; ui < spExp->uiRuleCount; ui++){
855  spExp->spRelRules[ui].bEnabled = bEnable;
856  }
857  for(ui = 0; ui < spExp->uiUdtCount; ui++){
858  spExp->spRelUdts[ui].bEnabled = bEnable;
859  }
860 }
861 
874 void vApgexSetLastIndex(void* vpCtx, aint uiLastIndex){
875  apgex* spExp = (apgex*) vpCtx;
876  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
877  vExContext();
878  }
879  spExp->uiLastIndex = uiLastIndex;
880 }
881 
889  apgex* spExp = (apgex*) vpCtx;
890  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
891  vExContext();
892  }
893  if(!spExp->vpParser){
894  XTHROW(spExp->spException, s_cpNoPattern);
895  }
896  apgex_properties sProps;
897  memset(&sProps, 0, sizeof(apgex_properties));
898  sProps.vpParser = spExp->vpParser;
899  sProps.vpAst = spExp->vpAst;
900  sProps.vpTrace = spExp->vpTrace;
901  sProps.cpPattern = (const char*)vpVecFirst(spExp->vpVecPattern);
902  sProps.cpFlags = (const char*)vpVecFirst(spExp->vpVecFlags);
903  sProps.uiLastIndex = spExp->uiLastIndex;
904  sProps.bDefaultMode = spExp->bDefaultMode;
905  sProps.bGlobalMode = spExp->bGlobalMode;
906  sProps.bStickyMode = spExp->bStickyMode;
907  sProps.bPpptMode = spExp->bPpptMode;
908  sProps.bTraceMode = spExp->bTraceMode;
909  sProps.bTraceHtmlMode = spExp->bTraceHtmlMode;
910  if(spExp->bReplaceMode){
913  }else{
914  sProps.sOriginalSource.acpPhrase = (const achar*)vpVecFirst(spExp->vpVecSource);
915  sProps.sOriginalSource.uiLength = uiVecLen(spExp->vpVecSource);
916  }
917  sProps.sLastSource.acpPhrase = (const achar*)vpVecFirst(spExp->vpVecSource);
918  sProps.sLastSource.uiLength = uiVecLen(spExp->vpVecSource);
919  if(spExp->spLastMatch){
920  sProps.sLastMatch = *spExp->spLastMatch;
921  }
922  if(spExp->spLeftContext){
923  sProps.sLeftContext = *spExp->spLeftContext;
924  }
925  if(spExp->spRightContext){
926  sProps.sRightContext = *spExp->spRightContext;
927  }
928  return sProps;
929 }
930 
957 void* vpApgexGetAst(void* vpCtx){
958  apgex* spExp = (apgex*) vpCtx;
959  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
960  vExContext();
961  }
962  if(!spExp->vpParser){
963  XTHROW(spExp->spException, s_cpNoPattern);
964  }
965  return spExp->vpAst;
966 }
967 
984 void* vpApgexGetTrace(void* vpCtx){
985  apgex* spExp = (apgex*) vpCtx;
986  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
987  vExContext();
988  }
989  if(!spExp->vpParser){
990  XTHROW(spExp->spException, s_cpNoPattern);
991  }
992  return spExp->vpTrace;
993 }
994 
1009 void* vpApgexGetParser(void* vpCtx){
1010  apgex* spExp = (apgex*) vpCtx;
1011  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
1012  vExContext();
1013  }
1014  if(!spExp->vpParser){
1015  XTHROW(spExp->spException, s_cpNoPattern);
1016  }
1017  return spExp->vpParser;
1018 }
1019 
1028 void vApgexDisplayProperties(void* vpCtx, apgex_properties* spProperties, const char* cpFileName){
1029  apgex* spExp = (apgex*) vpCtx;
1030  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
1031  vExContext();
1032  }
1033  if(!spExp->vpParser){
1034  XTHROW(spExp->spException, s_cpNoPattern);
1035  }
1036  spExp->spDisplay = stdout;
1037  if(cpFileName){
1038  spExp->spDisplay = fopen(cpFileName, "wb");
1039  if(!spExp->spDisplay){
1040  char caBuf[BUF_SIZE];
1041  snprintf(caBuf, BUF_SIZE, "can't open file %s for writing", cpFileName);
1042  XTHROW(spExp->spException, caBuf);
1043  }
1044  }
1045  FILE* spOut = spExp->spDisplay;
1046  apgex_phrase sOutPhrase = {};
1047  fprintf(spOut, "PROPERTIES:\n");
1048  fprintf(spOut, "Pattern:\n");
1049  fprintf(spOut, "%s", (char*)vpVecFirst(spExp->vpVecPattern));
1050  fprintf(spOut, "\n");
1051  fprintf(spOut, " Flags: \"%s\"\n", (char*)vpVecFirst(spExp->vpVecFlags));
1052  fprintf(spOut, " default: %s\n", cpBool(spProperties->bDefaultMode));
1053  fprintf(spOut, " global: %s\n", cpBool(spProperties->bGlobalMode));
1054  fprintf(spOut, " sticky: %s\n", cpBool(spProperties->bStickyMode));
1055  fprintf(spOut, " pppt: %s\n", cpBool(spProperties->bPpptMode));
1056  if(spProperties->bTraceMode){
1057  if(spProperties->bTraceHtmlMode){
1058  fprintf(spOut, " trace: yes(html)\n");
1059  }else{
1060  fprintf(spOut, " trace: yes(ascii)\n");
1061  }
1062  }else{
1063  fprintf(spOut, " trace: no\n");
1064  }
1065  if(spExp->bReplaceMode){
1066  fprintf(spOut, "Original Source: ");
1067  sOutPhrase.sPhrase = spProperties->sOriginalSource;
1068  vPrintPhrase(spExp, &sOutPhrase, spOut);
1069  fprintf(spOut, "Replaced Source: ");
1070  sOutPhrase.sPhrase = spProperties->sLastSource;
1071  vPrintPhrase(spExp, &sOutPhrase, spOut);
1072  }else{
1073  fprintf(spOut, "Original Source: ");
1074  sOutPhrase.sPhrase = spProperties->sOriginalSource;
1075  vPrintPhrase(spExp, &sOutPhrase, spOut);
1076  }
1077  fprintf(spOut, " Last Index: %"PRIuMAX"\n", (luint)spExp->uiLastIndex);
1078  fprintf(spOut, " Last Match: ");
1079  vPrintPhrase(spExp, &spProperties->sLastMatch, spOut);
1080  fprintf(spOut, " Left Context: ");
1081  vPrintPhrase(spExp, &spProperties->sLeftContext, spOut);
1082  fprintf(spOut, " Right Context: ");
1083  vPrintPhrase(spExp, &spProperties->sRightContext, spOut);
1084  if(spOut && (spOut != stdout)){
1085  fclose(spOut);
1086  spExp->spDisplay = NULL;
1087  }
1088 }
1089 
1098 void vApgexDisplayPhrase(void* vpCtx, apgex_phrase* spPhrase, const char* cpFileName){
1099  apgex* spExp = (apgex*) vpCtx;
1100  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
1101  vExContext();
1102  }
1103  if(!spPhrase){
1104  XTHROW(spExp->spException, "phrase to display, spPhrase, cannot be NULL");
1105  }
1106  spExp->spDisplay = stdout;
1107  if(cpFileName){
1108  spExp->spDisplay = fopen(cpFileName, "wb");
1109  if(!spExp->spDisplay){
1110  char caBuf[BUF_SIZE];
1111  snprintf(caBuf, BUF_SIZE, "can't open file %s for writing", cpFileName);
1112  XTHROW(spExp->spException, caBuf);
1113  }
1114  }
1115  vPrintPhrase(spExp, spPhrase, spExp->spDisplay);
1116  if(spExp->spDisplay && (spExp->spDisplay != stdout)){
1117  fclose(spExp->spDisplay);
1118  spExp->spDisplay = NULL;
1119  }
1120 }
1121 
1129 void vApgexDisplayResult(void* vpCtx, apgex_result* spResult, const char* cpFileName){
1130  apgex* spExp = (apgex*) vpCtx;
1131  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
1132  vExContext();
1133  }
1134  if(!spResult){
1135  XTHROW(spExp->spException, "result to display, spResult, cannot be NULL");
1136  }
1137  spExp->spDisplay = stdout;
1138  if(cpFileName){
1139  spExp->spDisplay = fopen(cpFileName, "wb");
1140  if(!spExp->spDisplay){
1141  char caBuf[BUF_SIZE];
1142  snprintf(caBuf, BUF_SIZE, "can't open file %s for writing", cpFileName);
1143  XTHROW(spExp->spException, caBuf);
1144  }
1145  }
1146  FILE* spOut = spExp->spDisplay;
1147  fprintf(spOut, "RESULT:\n");
1148  fprintf(spOut, "result : ");
1149  if(!spResult->spResult){
1150  fprintf(spOut, "no match\n");
1151  }else{
1152  vPrintPhrase(spExp, spResult->spResult, spOut);
1153  fprintf(spOut, "left context : ");
1154  vPrintPhrase(spExp, spResult->spLeftContext, spOut);
1155  fprintf(spOut, "right context: ");
1156  vPrintPhrase(spExp, spResult->spRightContext, spOut);
1157  fprintf(spOut, "uiLastIndex : %"PRIuMAX"\n", (luint)spResult->uiLastIndex);
1158  fprintf(spOut, "node hits : %"PRIuMAX"\n", (luint)spResult->uiNodeHits);
1159  fprintf(spOut, "tree depth : %"PRIuMAX"\n", (luint)spResult->uiTreeDepth);
1160  if(spResult->uiRuleCount){
1161  aint ui, uj;
1162  fprintf(spOut, "\nRULES:\n");
1163  for(ui = 0; ui < spResult->uiRuleCount; ui++){
1164  if(ui > 0){
1165  fprintf(spOut, "\n");
1166  }
1167  fprintf(spOut, "%s: phrases: %"PRIuMAX"\n", spResult->spRules[ui].cpRuleName, (luint)spResult->spRules[ui].uiPhraseCount);
1168  for(uj = 0; uj < spResult->spRules[ui].uiPhraseCount; uj++){
1169  vPrintPhrase(spExp, &spResult->spRules[ui].spPhrases[uj], spOut);
1170  }
1171  }
1172  }
1173  }
1174  if(spOut && (spOut != stdout)){
1175  fclose(spOut);
1176  spExp->spDisplay = NULL;
1177  }
1178  }
1179 
1180 void vApgexDisplayPatternErrors(void* vpCtx, const char* cpFileName){
1181  apgex* spExp = (apgex*) vpCtx;
1182  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
1183  vExContext();
1184  }
1185  spExp->spDisplay = stdout;
1186  if(cpFileName){
1187  spExp->spDisplay = fopen(cpFileName, "wb");
1188  if(!spExp->spDisplay){
1189  char caBuf[BUF_SIZE];
1190  snprintf(caBuf, BUF_SIZE, "can't open file %s for writing", cpFileName);
1191  XTHROW(spExp->spException, caBuf);
1192  }
1193  }
1194  FILE* spOut = spExp->spDisplay;
1195  void* vpMsgs = vpApiGetErrorLog(spExp->vpApi);
1196  if(!bMsgsValidate(vpMsgs)){
1197  vExContext();
1198  }
1199  const char* cpMsg = cpMsgsFirst(vpMsgs);
1200  while(cpMsg){
1201  fprintf(spOut, "%s\n", cpMsg);
1202  cpMsg = cpMsgsNext(vpMsgs);
1203  }
1204 
1205  if(spOut && (spOut != stdout)){
1206  fclose(spOut);
1207  spExp->spDisplay = NULL;
1208  }
1209 }
1210 
1222 void vApgexDefineUDT(void* vpCtx, const char* cpName, parser_callback pfnUdt){
1223  apgex* spExp = (apgex*) vpCtx;
1224  if(!vpCtx || (spExp->vpValidate != s_vpMagicNumber)){
1225  vExContext();
1226  }
1227  if(!spExp->vpParser){
1228  XTHROW(spExp->spException, s_cpNoPattern);
1229  }
1230  udt_r* spUdt = spFindUdt(spExp, cpName);
1231  if(!spUdt){
1232  char caBuf[BUF_SIZE];
1233  snprintf(caBuf, BUF_SIZE, "pattern has no UDT named %s", cpName);
1234  XTHROW(spExp->spException, caBuf);
1235  }
1236  vParserSetUdtCallback(spExp->vpParser, spUdt->uiUdtIndex, pfnUdt);
1237 // spExp->spRelUdts[spUdt->uiUdtIndex].pfnUdt = pfnUdt;
1238 }
1239 
1240 // ///////////////////////////////////////////////////////////////////////////////
1241 // STATIC FUNCTIONS
1242 // ///////////////////////////////////////////////////////////////////////////////
1243 static inline void vMakeAbsPhrase(apgex* spExp, phrase_r* spRelPhrase, apgex_phrase* spAbsPhrase){
1244  spAbsPhrase->sPhrase.acpPhrase = (achar*)vpVecFirst(spExp->vpVecSource) + spRelPhrase->uiSourceOffset;
1245  spAbsPhrase->sPhrase.uiLength = spRelPhrase->uiLength;
1246  spAbsPhrase->uiPhraseOffset = spRelPhrase->uiSourceOffset;
1247 }
1248 
1249 static inline void vMakeRelPhrase(apgex* spExp, aint uiSourceOffset, aint uiLen, phrase_r* spPhrase){
1250  spPhrase->uiSourceOffset = uiSourceOffset;
1251  spPhrase->uiLength = uiLen;
1252 }
1253 
1254 static inline char* cpBool(abool bVal){
1255  if(bVal){
1256  return "yes";
1257  }
1258  return "no";
1259 }
1260 
1261 static void vNamePhrase(apgex* spExp, achar* acpName, aint uiNameLen, apg_phrase* spPhrase){
1262  rule_r* spRule = NULL;
1263  udt_r* spUdt = NULL;
1264  char* cpNameStr;
1265  phrase_r* spRelPhrase;
1266  achar* acpSource = (achar*)vpVecFirst(spExp->vpVecSource);
1267  aint ui;
1268  char caBuf[BUF_SIZE];
1269  void* vpVecTmp = spExp->vpVecStrings;
1270  vVecClear(vpVecTmp);
1271  memset(spPhrase, 0, sizeof(*spPhrase));
1272  // look up name
1273  for(ui = 0; ui < uiNameLen; ui++){
1274  char cChar = (char)acpName[ui];
1275  vpVecPush(vpVecTmp, &cChar);
1276  }
1277  vpVecPush(vpVecTmp, &s_cZero);
1278  cpNameStr = (char*)vpVecFirst(vpVecTmp);
1279  spRule = spFindRule(spExp, (const char*)cpNameStr);
1280  if(spRule){
1281  if(spRule->bEnabled && spRule->uiFirstPhrase != APG_INFINITE){
1282  spRelPhrase = (phrase_r*)vpVecAt(spExp->vpVecRelPhrases, spRule->uiFirstPhrase);
1283  spPhrase->acpPhrase = &acpSource[spRelPhrase->uiSourceOffset];
1284  spPhrase->uiLength = spRelPhrase->uiLength;
1285  }
1286  goto found;
1287  }
1288  spUdt = spFindUdt(spExp, (const char*)cpNameStr);
1289  if(spUdt){
1290  if(spUdt->bEnabled && spUdt->uiFirstPhrase != APG_INFINITE){
1291  spRelPhrase = (phrase_r*)vpVecAt(spExp->vpVecRelPhrases, spUdt->uiFirstPhrase);
1292  spPhrase->acpPhrase = &acpSource[spRelPhrase->uiSourceOffset];
1293  spPhrase->uiLength = spRelPhrase->uiLength;
1294  }
1295  goto found;
1296  }
1297  snprintf(caBuf, BUF_SIZE, "replacement error: &<%s> not a valid rule or UDT name", (char*)cpNameStr);
1298  vVecClear(vpVecTmp);
1299  XTHROW(spExp->spException, caBuf);
1300  found:;
1301  vVecClear(vpVecTmp);
1302 }
1303 static void vReplaceFunc(apgex* spExp, apgex_result* spResult, pfn_replace pfnFunc, void* vpUser){
1304  vVecClear(spExp->vpVecReplacement);
1305  apgex_properties sProps = sApgexProperties(spExp);
1306  apg_phrase sPhrase = pfnFunc(spResult, &sProps, vpUser);
1307  if(sPhrase.acpPhrase && sPhrase.uiLength){
1308  vpVecPushn(spExp->vpVecReplacement, (void*)sPhrase.acpPhrase, sPhrase.uiLength);
1309  }
1310 }
1311 
1312 static void vReplacement(apgex* spExp, apgex_result* spResult){
1313  // the raw replacement achar array is in vpVecReplaceRaw
1314  // make the substituted replacement achar array is in vpVecReplacement
1315  // make the string version of the substituted replacement achar array is in vpVecReplaceString
1316  vVecClear(spExp->vpVecReplacement);
1317  achar* acpRaw = (achar*)vpVecFirst(spExp->vpVecReplaceRaw);
1318  aint uiRawLen = uiVecLen(spExp->vpVecReplaceRaw);
1319  aint ui, uii, uj, uiNameLen;
1320  apg_phrase *spMatch, *spLeft, *spRight;
1321  char caBuf[BUF_SIZE];
1322  if(uiRawLen > 1){
1323  ui = 0;
1324  uii = 1;
1325  spMatch = &spResult->spResult->sPhrase;
1326  spLeft = &spResult->spLeftContext->sPhrase;
1327  spRight = &spResult->spRightContext->sPhrase;
1328  while(ui < uiRawLen){
1329  while(APG_TRUE){
1330  if(acpRaw[ui] == DOLLAR){
1331  if(uii >= uiRawLen){
1332  XTHROW(spExp->spException, "replacement error: $ found at end of string - must be $`, $&, $', $$ or $<rulename>");
1333  }
1334  if(acpRaw[uii] == DOLLAR){
1335  vpVecPush(spExp->vpVecReplacement, &acpRaw[ui]);
1336  ui += 2;
1337  uii += 2;
1338  break;
1339  }
1340  if(acpRaw[uii] == UNDER){
1341  if(spMatch->uiLength){
1343  }
1344  ui += 2;
1345  uii += 2;
1346  break;
1347  }
1348  if(acpRaw[uii] == AMP){
1349  if(spMatch->uiLength){
1350  vpVecPushn(spExp->vpVecReplacement, (void*)spMatch->acpPhrase, spMatch->uiLength);
1351  }
1352  ui += 2;
1353  uii += 2;
1354  break;
1355  }
1356  if(acpRaw[uii] == ACCENT){
1357  if(spLeft->uiLength){
1358  vpVecPushn(spExp->vpVecReplacement, (void*)spLeft->acpPhrase, spLeft->uiLength);
1359  }
1360  ui += 2;
1361  uii += 2;
1362  break;
1363  }
1364  if(acpRaw[uii] == APOS){
1365  if(spRight->uiLength){
1366  vpVecPushn(spExp->vpVecReplacement, (void*)spRight->acpPhrase, spRight->uiLength);
1367  }
1368  ui += 2;
1369  uii += 2;
1370  break;
1371  }
1372  if(acpRaw[uii] == LANGLE){
1373  for(uj = uii + 1; uj < uiRawLen; uj++){
1374  if(acpRaw[uj] == RANGLE){
1375  uiNameLen = uj - uii -1;
1376  if(uiNameLen == 0){
1377  XTHROW(spExp->spException, "replacement error: &<> - no rule name");
1378  }
1379  apg_phrase sPhrase = {};
1380  vNamePhrase(spExp, &acpRaw[uii + 1], uiNameLen, &sPhrase);
1381  if(sPhrase.acpPhrase){
1382  vpVecPushn(spExp->vpVecReplacement, (void*)sPhrase.acpPhrase, sPhrase.uiLength);
1383  }
1384  // else if no matched phrase for this rule name replace &<rulename> with empty string
1385  ui += uiNameLen + 3;
1386  uii = ui + 1;
1387  goto name;
1388  }
1389  }
1390  XTHROW(spExp->spException, "replacement error: found &< but closing angle bracket, >, not found");
1391  name:;
1392  break;
1393  }
1394  snprintf(caBuf, BUF_SIZE, "replacement error: $ followed by %"PRIuMAX" - must be $`, $&, $', $$ or $<rulename>", (luint)acpRaw[uii]);
1395  XTHROW(spExp->spException, caBuf);
1396  }else{
1397  vpVecPush(spExp->vpVecReplacement, &acpRaw[ui]);
1398  ui++;
1399  uii++;
1400  }
1401  break;
1402  }
1403  }
1404  }
1405 }
1406 static void vReplace(apgex* spExp, apgex_result* spResult){
1407  aint uiReplaceLen;
1408  achar* acpRight = NULL;
1409  aint uiRight;
1410  apg_phrase *spMatch = &spResult->spResult->sPhrase;
1411  apg_phrase *spLeft = &spResult->spLeftContext->sPhrase;
1412  apg_phrase *spRight = &spResult->spRightContext->sPhrase;
1413  uiReplaceLen = uiVecLen(spExp->vpVecReplacement);
1414  if(spRight->uiLength){
1415  // save right context
1416  uiRight = uiVecLen(spExp->vpVecReplacement);
1417  vpVecPushn(spExp->vpVecReplacement, (void*)spRight->acpPhrase, spRight->uiLength);
1418  acpRight = (achar*)vpVecAt(spExp->vpVecReplacement, uiRight);
1419  }
1420  // pop off the phrase and its right context
1421  aint uiTmp = spMatch->uiLength + spRight->uiLength;
1422  if(uiTmp){
1423  vpVecPopi(spExp->vpVecSource, spLeft->uiLength);
1424  }
1425  // push on the replacement string
1426  if(uiReplaceLen){
1427  vpVecPushn(spExp->vpVecSource, vpVecFirst(spExp->vpVecReplacement), uiReplaceLen);
1428  }
1429  if(spRight->uiLength){
1430  // push on the right context
1431  vpVecPushn(spExp->vpVecSource, (void*)acpRight, spRight->uiLength);
1432  }
1433  spExp->uiLastIndex += uiReplaceLen;
1434  spExp->uiLastIndex -= spMatch->uiLength;
1435  spExp->spRightContext->uiPhraseOffset += uiReplaceLen;
1436  spExp->spRightContext->uiPhraseOffset -= spMatch->uiLength;
1437 }
1438 
1439 static void vExecResult(apgex* spExp, apgex_result* spResult){
1440  parser_config sConfig = {};
1441  while(APG_TRUE){
1442  sConfig.uiInputLength = uiVecLen(spExp->vpVecSource);
1443  if(spExp->uiLastIndex >= sConfig.uiInputLength){
1444  // no match - no substring to parse
1445  break;
1446  }
1447 
1448  sConfig.acpInput = (achar*)vpVecFirst(spExp->vpVecSource);
1449  sConfig.bParseSubString = APG_TRUE;
1450  sConfig.uiSubStringBeg = spExp->uiLastIndex;
1451  sConfig.vpUserData = (void*)spExp;
1452  if(spExp->vpTrace){
1453  TRACE_APGEX_HEADER(spExp->vpTrace);
1454  }
1455  if(spExp->bDefaultMode){
1456  vMatchDefault(spExp, &sConfig, spResult);
1457  spExp->uiLastIndex = 0;
1458  }else if(spExp->bGlobalMode){
1459  vMatchGlobal(spExp, &sConfig, spResult);
1460  if(!spResult->spResult){
1461  spExp->uiLastIndex = 0;
1462  }
1463  }else if(spExp->bStickyMode){
1464  vMatchSticky(spExp, &sConfig, spResult);
1465  if(!spResult->spResult){
1466  spExp->uiLastIndex = 0;
1467  }
1468  }
1469  spResult->uiLastIndex = spExp->uiLastIndex;
1470  if(spExp->vpTrace){
1471  TRACE_APGEX_FOOTER(spExp->vpTrace);
1472  TRACE_DTOR(spExp->vpTrace);
1473  spExp->vpTrace = NULL;
1474  }
1475  break;
1476  }
1477 }
1478 
1479 static abool bExecTest(apgex* spExp){
1480  abool bReturn = APG_FALSE;
1481  parser_config sConfig = {};
1482  while(APG_TRUE){
1483  sConfig.uiInputLength = uiVecLen(spExp->vpVecSource);
1484  if(spExp->uiLastIndex >= sConfig.uiInputLength){
1485  // no match - no substring to parse
1486  break;
1487  }
1488 
1489  // check that all UDTs are defined
1490  aint ui;
1491  for(ui = 0; ui < spExp->uiUdtCount; ui++){
1492  if(!spExp->spRelUdts[ui].pfnUdt){
1493  char caBuf[BUF_SIZE];
1494  snprintf(caBuf, BUF_SIZE, "UDT \"%s\" not defined", spExp->spRelUdts[ui].cpUdtName);
1495  XTHROW(spExp->spException, caBuf);
1496  }
1497  }
1498  sConfig.acpInput = (achar*)vpVecFirst(spExp->vpVecSource);
1499  sConfig.bParseSubString = APG_TRUE;
1500  sConfig.uiSubStringBeg = spExp->uiLastIndex;
1501  sConfig.vpUserData = (void*)spExp;
1502  if(spExp->vpTrace){
1503  TRACE_APGEX_HEADER(spExp->vpTrace);
1504  }
1505  if(spExp->bDefaultMode){
1506  bReturn = bTestDefault(spExp, &sConfig);
1507  spExp->uiLastIndex = 0;
1508  }else if(spExp->bGlobalMode){
1509  bReturn = bTestGlobal(spExp, &sConfig);
1510  if(!bReturn){
1511  spExp->uiLastIndex = 0;
1512  }
1513  }else if(spExp->bStickyMode){
1514  bReturn = bTestSticky(spExp, &sConfig);
1515  if(!bReturn){
1516  spExp->uiLastIndex = 0;
1517  }
1518  }
1519  if(spExp->vpTrace){
1520  TRACE_APGEX_FOOTER(spExp->vpTrace);
1521  TRACE_DTOR(spExp->vpTrace);
1522  spExp->vpTrace = NULL;
1523  }
1524  break;
1525  }
1526  return bReturn;
1527 }
1528 
1529 static void vDecodeFlags(apgex* spExp, const char* cpFlags){
1530  spExp->bDefaultMode = APG_TRUE;
1531  aint ui = 0;
1532  aint uiFlagsLen = 0;
1533  if(cpFlags){
1534  uiFlagsLen = (aint)strlen(cpFlags);
1535  if(uiFlagsLen){
1536  // save a copy of the original flags string
1537  vpVecPushn(spExp->vpVecFlags, (void*)cpFlags, (aint)(strlen(cpFlags) + 1));
1538  char caBuf[BUF_SIZE];
1539  for(; ui < uiFlagsLen; ui++){
1540  switch(cpFlags[ui]){
1541  case 'g':
1542  if(!spExp->bStickyMode){
1543  spExp->bGlobalMode = APG_TRUE;
1544  spExp->bDefaultMode = APG_FALSE;
1545  }
1546  break;
1547  case 'y':
1548  if(!spExp->bGlobalMode){
1549  spExp->bStickyMode = APG_TRUE;
1550  spExp->bDefaultMode = APG_FALSE;
1551  }
1552  break;
1553  case 't':
1554  if(!spExp->bTraceMode){
1555  spExp->bTraceMode = APG_TRUE;
1556  }
1557  break;
1558  case 'h':
1559  if(spExp->bTraceMode){
1560  spExp->bTraceHtmlMode = APG_TRUE;
1561  }else{
1562  XTHROW(spExp->spException, "%'h' flag (for HTML trace output) must follow 't' flag");
1563  }
1564  break;
1565  case 'p':
1566  spExp->bPpptMode = APG_TRUE;
1567  break;
1568  default:
1569  snprintf(caBuf, BUF_SIZE, "%c unrecognized flag character, must be one or more of \"gyta\"", cpFlags[ui]);
1570  XTHROW(spExp->spException, caBuf);
1571  break;
1572  }
1573  }
1574  }
1575  }
1576  TRACE_APGEX_CHECK(spExp);
1577  if((cpFlags == NULL) || (uiFlagsLen == 0)){
1578  // save an empty string
1579  vpVecPush(spExp->vpVecFlags, &s_cZero);
1580  }
1581 }
1582 
1583 static void vConstructParser(apgex* spExp){
1584  char* cpPattern = (char*)vpVecFirst(spExp->vpVecPattern);
1585  aint uiPatternLen = (aint)strlen(cpPattern);
1586  if(!cpPattern || (uiPatternLen <= 1)){
1587  XTHROW(spExp->spException, "attmpting to construct the parser but the pattern is not yet defined");
1588  }
1589  vApiInClear(spExp->vpApi);
1590  cpApiInString(spExp->vpApi, cpPattern);
1591  vApiInValidate(spExp->vpApi, APG_FALSE);
1592  vApiSyntax(spExp->vpApi, APG_FALSE);
1593  vApiOpcodes(spExp->vpApi);
1594  bApiAttrs(spExp->vpApi);
1595  if(spExp->bPpptMode){
1596  vApiPppt(spExp->vpApi, NULL, 0);
1597  }
1598  spExp->vpParser = vpApiOutputParser(spExp->vpApi);
1599  TRACE_APGEX_OUTPUT(spExp);
1600  spExp->vpAst = vpAstCtor(spExp->vpParser);
1601 }
1602 
1603 static void vInitRules(apgex* spExp){
1604  if(!spExp->vpParser){
1605  XTHROW(spExp->spException, "attempting to initialize rules and UDTS but parser not defined");
1606  }
1607 
1608  // set all rule and UDT call backs, even if disabled
1609  // we want the AST to collect records for ALL rules and UDTs
1610  aint ui;
1611  parser* spParser = (parser*)spExp->vpParser;
1612  spExp->uiRuleCount = spParser->uiRuleCount;
1613  spExp->uiUdtCount = spParser->uiUdtCount;
1614  spExp->spRelRules = (rule_r*)vpVecPushn(spExp->vpVecRelRules, NULL, spExp->uiRuleCount);
1615  for(ui = 0; ui < spExp->uiRuleCount; ui++){
1616  spExp->spRelRules[ui].cpRuleName = spParser->spRules[ui].cpRuleName;
1617  spExp->spRelRules[ui].uiRuleIndex = spParser->spRules[ui].uiRuleIndex;
1618  spExp->spRelRules[ui].uiFirstPhrase = APG_UNDEFINED;
1619  spExp->spRelRules[ui].uiLastPhrase = APG_UNDEFINED;
1620  spExp->spRelRules[ui].bEnabled = APG_FALSE;
1621  }
1622  if(spExp->uiUdtCount){
1623  // initialize the UDT list
1624  spExp->spRelUdts = (udt_r*)vpVecPushn(spExp->vpVecRelUdts, NULL, spExp->uiUdtCount);
1625  for(ui = 0; ui < spExp->uiUdtCount; ui++){
1626  spExp->spRelUdts[ui].cpUdtName = spParser->spUdts[ui].cpUdtName;
1627  spExp->spRelUdts[ui].uiUdtIndex = spParser->spUdts[ui].uiUdtIndex;
1628  spExp->spRelUdts[ui].uiFirstPhrase = APG_UNDEFINED;
1629  spExp->spRelUdts[ui].uiLastPhrase = APG_UNDEFINED;
1630  spExp->spRelUdts[ui].bEnabled = APG_FALSE;
1631  }
1632  }
1633 }
1634 static void vInitCallbacks(apgex* spExp){
1635  if(!spExp->vpParser){
1636  XTHROW(spExp->spException, "attempting to initialize rules and UDTS but parser not defined");
1637  }
1638 
1639  // set all rule and UDT call backs, even if disabled
1640  // we want the AST to collect records for ALL rules and UDTs
1641  aint ui;
1642  for(ui = 0; ui < spExp->uiRuleCount; ui++){
1643  vAstSetRuleCallback(spExp->vpAst, ui, pfnRuleCallback);
1644  }
1645  if(spExp->uiUdtCount){
1646  // initialize the UDT list
1647  for(ui = 0; ui < spExp->uiUdtCount; ui++){
1648  vAstSetUdtCallback(spExp->vpAst, ui, pfnUdtCallback);
1649  }
1650  }
1651 }
1652 
1653 static void vResetCallbacks(apgex* spExp){
1654  if(!spExp->vpParser){
1655  XTHROW(spExp->spException, "attempting to initialize rules and UDTS but parser not defined");
1656  }
1657 
1658  // set all rule and UDT call backs, even if disabled
1659  // we want the AST to collect records for ALL rules and UDTs
1660  aint ui;
1661  for(ui = 0; ui < spExp->uiRuleCount; ui++){
1662  vAstSetRuleCallback(spExp->vpAst, ui, NULL);
1663  }
1664  if(spExp->uiUdtCount){
1665  // initialize the UDT list
1666  for(ui = 0; ui < spExp->uiUdtCount; ui++){
1667  vAstSetUdtCallback(spExp->vpAst, ui, NULL);
1668  }
1669  }
1670 }
1671 
1672 static void vMatchResult(apgex* spExp, parser_config* spConfig, parser_state* spState, apgex_result* spResult){
1673  // translate the AST to get the relative phrases
1674  vAstTranslate(spExp->vpAst, (void*)spExp);
1675 
1676  // // push 3 relative phrases for the result, left and right context
1677  phrase_r* spRelResult = (phrase_r*)vpVecPush(spExp->vpVecRelPhrases, NULL);
1678  phrase_r* spRelLeft = (phrase_r*)vpVecPush(spExp->vpVecRelPhrases, NULL);
1679  phrase_r* spRelRight = (phrase_r*)vpVecPush(spExp->vpVecRelPhrases, NULL);
1680  spRelResult->uiNext = APG_UNDEFINED;
1681  spRelLeft->uiNext = APG_UNDEFINED;
1682  spRelRight->uiNext = APG_UNDEFINED;
1683  vMakeRelPhrase(spExp, spConfig->uiSubStringBeg, spState->uiPhraseLength, spRelResult);
1684  vMakeRelPhrase(spExp, 0, spConfig->uiSubStringBeg, spRelLeft);
1685  aint uiOffset = spConfig->uiSubStringBeg + spState->uiPhraseLength;
1686  vMakeRelPhrase(spExp, uiOffset, (spConfig->uiInputLength - uiOffset), spRelRight);
1687 
1688  // absolute phrases can now be generated
1689  aint uiCount = uiVecLen(spExp->vpVecRelPhrases);
1690  apgex_phrase* spAbsPhrases = (apgex_phrase*)vpVecPushn(spExp->vpVecPhrases, NULL, uiCount);
1691  apgex_phrase* spAbsPhrase = spAbsPhrases;
1692 
1693  // make the result
1694  vMakeAbsPhrase(spExp, spRelResult, spAbsPhrase);
1695  spExp->spLastMatch = spAbsPhrase;
1696  spResult->spResult = spAbsPhrase++;
1697 
1698  // make the left context
1699  vMakeAbsPhrase(spExp, spRelLeft, spAbsPhrase);
1700  spExp->spLeftContext = spAbsPhrase;
1701  spResult->spLeftContext = spAbsPhrase++;
1702 
1703  // make the right context
1704  vMakeAbsPhrase(spExp, spRelRight, spAbsPhrase);
1705  spExp->spRightContext = spAbsPhrase;
1706  spResult->spRightContext = spAbsPhrase++;
1707 
1708  // some stats
1709  spResult->uiTreeDepth = spState->uiMaxTreeDepth;
1710  spResult->uiNodeHits = spState->uiHitCount;
1711 
1712  phrase_r sRelPhrase;
1713  phrase_r* spRelPhrases = (phrase_r*)vpVecFirst(spExp->vpVecRelPhrases);
1714  spResult->uiRuleCount = spExp->uiEnabledRuleCount + spExp->uiEnabledUdtCount;
1715  if(spResult->uiRuleCount){
1716  spResult->spRules = (apgex_rule*)vpVecPushn(spExp->vpVecRules, NULL, spResult->uiRuleCount);
1717  }
1718  if(spExp->uiEnabledRuleCount){
1719  // add the rules
1720  apgex_rule* spAbsRule = spResult->spRules;
1721  // for each enabled rule, add the absolute phrases sequentially
1722  rule_r* spRule = spExp->spRelRules;
1723  rule_r* spRuleEnd = spRule + spExp->uiRuleCount;
1724  phrase_r* spListPhrase;
1725  for(; spRule < spRuleEnd; spRule++){
1726  if(spRule->bEnabled){
1727  spAbsRule->cpRuleName = spRule->cpRuleName;
1728  spAbsRule->uiIndex = spRule->uiRuleIndex;
1729  spAbsRule->uiPhraseCount = spRule->uiPhraseCount;
1730  spAbsRule->spPhrases = spAbsPhrase;
1731  // follow the linked list of relative phrases, building a sequential list of absolute phrases
1732  aint uiNext = spRule->uiFirstPhrase;
1733  aint uiSanityCount = 0;
1734  while(uiNext != APG_UNDEFINED){
1735  spListPhrase = spRelPhrases + uiNext;
1736  vMakeRelPhrase(spExp, spListPhrase->uiSourceOffset, spListPhrase->uiLength, &sRelPhrase);
1737  vMakeAbsPhrase(spExp, &sRelPhrase, spAbsPhrase);
1738  uiNext = spListPhrase->uiNext;
1739  spAbsPhrase++;
1740  uiSanityCount++;
1741  }
1742  if(uiSanityCount != spAbsRule->uiPhraseCount){
1743  XTHROW(spExp->spException, "number of phrases in linked list not the same as the phrase count");
1744  }
1745  spAbsRule++;
1746  }
1747  }
1748  }
1749  if(spExp->uiEnabledUdtCount){
1750  // add the UDTs
1751  apgex_rule* spAbsRule = &spResult->spRules[spExp->uiEnabledRuleCount];
1752  // for each enabled UDT, add the absolute phrases sequentially
1753  udt_r* spUdt = spExp->spRelUdts;
1754  udt_r* spUdtEnd = spUdt + spExp->uiUdtCount;
1755  phrase_r* spListPhrase;
1756  for(; spUdt < spUdtEnd; spUdt++){
1757  if(spUdt->bEnabled){
1758  spAbsRule->cpRuleName = spUdt->cpUdtName;
1759  spAbsRule->uiIndex = spUdt->uiUdtIndex;
1760  spAbsRule->uiPhraseCount = spUdt->uiPhraseCount;
1761  spAbsRule->spPhrases = spAbsPhrase;
1762  // follow the linked list of relative phrases, building a sequential list of absolute phrases
1763  aint uiNext = spUdt->uiFirstPhrase;
1764  aint uiSanityCount = 0;
1765  while(uiNext != APG_UNDEFINED){
1766  spListPhrase = spRelPhrases + uiNext;
1767  vMakeRelPhrase(spExp, spListPhrase->uiSourceOffset, spListPhrase->uiLength, &sRelPhrase);
1768  vMakeAbsPhrase(spExp, &sRelPhrase, spAbsPhrase);
1769  uiNext = spListPhrase->uiNext;
1770  spAbsPhrase++;
1771  uiSanityCount++;
1772  }
1773  if(uiSanityCount != spAbsRule->uiPhraseCount){
1774  XTHROW(spExp->spException, "number of phrases in linked list not the same as the phrase count");
1775  }
1776  spAbsRule++;
1777  }
1778  }
1779  }
1780 
1781  // remove all AST call back functions in case user wants to use the AST
1782  aint ui;
1783  for(ui = 0; ui < spExp->uiRuleCount; ui++){
1784  vAstSetRuleCallback(spExp->vpAst, ui, NULL);
1785  }
1786  if(spExp->uiUdtCount){
1787  for(ui = 0; ui < spExp->uiUdtCount; ui++){
1788  vAstSetUdtCallback(spExp->vpAst, ui, NULL);
1789  }
1790  }
1791  ui = 0;
1792 }
1793 static void vMatchDefault(apgex* spExp, parser_config* spConfig, apgex_result* spResult){
1794  parser_state sState;
1795  memset(spResult, 0, sizeof(*spResult));
1796  while(spConfig->uiSubStringBeg < spConfig->uiInputLength){
1797  if(spExp->vpTrace){
1798  TRACE_APGEX_SEPARATOR(spExp);
1799  }
1800  vParserParse(spExp->vpParser, spConfig, &sState);
1801  if(sState.uiState == ID_MATCH){
1802  vMatchResult(spExp, spConfig, &sState, spResult);
1803  break;
1804  }
1805  spConfig->uiSubStringBeg++;
1806  spExp->uiLastIndex++;
1807  }
1808 }
1809 
1810 static void vMatchGlobal(apgex* spExp, parser_config* spConfig, apgex_result* spResult){
1811  parser_state sState;
1812  memset(spResult, 0, sizeof(*spResult));
1813  while(spConfig->uiSubStringBeg < spConfig->uiInputLength){
1814  if(spExp->vpTrace){
1815  TRACE_APGEX_SEPARATOR(spExp);
1816  }
1817  vParserParse(spExp->vpParser, spConfig, &sState);
1818  if(sState.uiState == ID_MATCH){
1819  vMatchResult(spExp, spConfig, &sState, spResult);
1820  if(sState.uiPhraseLength){
1821  spExp->uiLastIndex = spConfig->uiSubStringBeg + sState.uiPhraseLength;
1822  }else{
1823  spExp->uiLastIndex = spConfig->uiSubStringBeg + 1;
1824  }
1825  break;
1826  }
1827  spConfig->uiSubStringBeg++;
1828  spExp->uiLastIndex++;
1829  }
1830 }
1831 
1832 static void vMatchSticky(apgex* spExp, parser_config* spConfig, apgex_result* spResult){
1833  parser_state sState;
1834  memset(spResult, 0, sizeof(*spResult));
1835  if(spExp->vpTrace){
1836  TRACE_APGEX_SEPARATOR(spExp);
1837  }
1838  vParserParse(spExp->vpParser, spConfig, &sState);
1839  if(sState.uiState == ID_MATCH){
1840  vMatchResult(spExp, spConfig, &sState, spResult);
1841  if(sState.uiPhraseLength){
1842  spExp->uiLastIndex = spConfig->uiSubStringBeg + sState.uiPhraseLength;
1843  }else{
1844  spExp->uiLastIndex = spConfig->uiSubStringBeg + 1;
1845  }
1846  }
1847 }
1848 
1849 static abool bTestDefault(apgex* spExp, parser_config* spConfig){
1850  abool bReturn = APG_FALSE;
1851  parser_state sState;
1852  while(spConfig->uiSubStringBeg < spConfig->uiInputLength){
1853  if(spExp->vpTrace){
1854  TRACE_APGEX_SEPARATOR(spExp);
1855  }
1856  vParserParse(spExp->vpParser, spConfig, &sState);
1857  if(sState.uiState == ID_MATCH){
1858  bReturn = APG_TRUE;
1859  break;
1860  }
1861  spConfig->uiSubStringBeg++;
1862  spExp->uiLastIndex++;
1863  }
1864  return bReturn;
1865 }
1866 
1867 static abool bTestGlobal(apgex* spExp, parser_config* spConfig){
1868  abool bReturn = APG_FALSE;
1869  parser_state sState;
1870  while(spConfig->uiSubStringBeg < spConfig->uiInputLength){
1871  if(spExp->vpTrace){
1872  TRACE_APGEX_SEPARATOR(spExp);
1873  }
1874  vParserParse(spExp->vpParser, spConfig, &sState);
1875  if(sState.uiState == ID_MATCH){
1876  bReturn = APG_TRUE;
1877  if(sState.uiPhraseLength){
1878  spExp->uiLastIndex = spConfig->uiSubStringBeg + sState.uiPhraseLength;
1879  }else{
1880  spExp->uiLastIndex = spConfig->uiSubStringBeg + 1;
1881  }
1882  break;
1883  }
1884  spConfig->uiSubStringBeg++;
1885  spExp->uiLastIndex++;
1886  }
1887  return bReturn;
1888 }
1889 
1890 static abool bTestSticky(apgex* spExp, parser_config* spConfig){
1891  abool bReturn = APG_FALSE;
1892  parser_state sState;
1893  if(spExp->vpTrace){
1894  TRACE_APGEX_SEPARATOR(spExp);
1895  }
1896  vParserParse(spExp->vpParser, spConfig, &sState);
1897  if(sState.uiState == ID_MATCH){
1898  bReturn = APG_TRUE;
1899  if(sState.uiPhraseLength){
1900  spExp->uiLastIndex = spConfig->uiSubStringBeg + sState.uiPhraseLength;
1901  }else{
1902  spExp->uiLastIndex = spConfig->uiSubStringBeg + 1;
1903  }
1904  }
1905  return bReturn;
1906 }
1907 
1917 static void vPrintPhrase(apgex* spExp, apgex_phrase* spPhrase, FILE* spOut){
1918  if(spPhrase->sPhrase.uiLength){
1919  if(bIsPhraseAscii(&spPhrase->sPhrase)){
1920  aint ui = 0;
1921  char cChar;
1922  fprintf(spOut, "offset: %"PRIuMAX" length: %"PRIuMAX": '",
1923  (luint)spPhrase->uiPhraseOffset, (luint)spPhrase->sPhrase.uiLength);
1924  for(; ui < spPhrase->sPhrase.uiLength; ui++){
1925  cChar = (char)spPhrase->sPhrase.acpPhrase[ui];
1926  if(cChar == 9){
1927  fprintf(spOut, "\\t");
1928  continue;
1929  }
1930  if(cChar == 10){
1931  fprintf(spOut, "\\n");
1932  continue;
1933  }
1934  if(cChar == 13){
1935  fprintf(spOut, "\\r");
1936  continue;
1937  }
1938  fprintf(spOut, "%c", cChar);
1939  }
1940  fprintf(spOut, "'\n");
1941  }else{
1942  const char* cpLine;
1943  aint uiWordSize = (aint)sizeof(achar);
1944  uint8_t* ucpBytes = (uint8_t*)spPhrase->sPhrase.acpPhrase;
1945  long int iByteCount = (long int)(uiWordSize * spPhrase->sPhrase.uiLength);
1946  if(uiWordSize == 1){
1947  fprintf(spOut, "offset: %"PRIuMAX" length: %"PRIuMAX" bytes\n",
1948  (luint)spPhrase->uiPhraseOffset, (luint)spPhrase->sPhrase.uiLength);
1949  }else{
1950  fprintf(spOut, "offset: %"PRIuMAX" length: %"PRIuMAX", %d-byte, %s-endian words\n",
1951  (luint)spPhrase->uiPhraseOffset, (luint)spPhrase->sPhrase.uiLength, (int)uiWordSize, s_cpEndian);
1952  }
1953  cpLine = cpFmtFirstBytes(spExp->vpFmt, ucpBytes, iByteCount, FMT_CANONICAL, 0, 0);
1954  while(cpLine){
1955  fprintf(spOut, "%s", cpLine);
1956  cpLine = cpFmtNext(spExp->vpFmt);
1957  }
1958  }
1959  }else{
1960  fprintf(spOut, "''\n");
1961  }
1962 }
1963 static aint pfnRuleCallback(ast_data* spData){
1964  // Note: callback_data acpString, uiStringLength and uiParserOffset refer to the sub-string being parser.
1965  if(spData->uiState == ID_AST_PRE){
1966  apgex* spExp = (apgex*)spData->vpUserData;
1967  phrase_r* spLastPhrase;
1968  rule_r* spRule = &spExp->spRelRules[spData->uiIndex];
1969  if(spRule->bEnabled){
1970  // push this phrase on the list
1971  aint uiPhraseIndex = uiVecLen(spExp->vpVecRelPhrases);
1972  phrase_r* spPhrase = (phrase_r*)vpVecPush(spExp->vpVecRelPhrases, NULL);
1973  aint uiAbsoluteOffset = spData->uiPhraseOffset;
1974  vMakeRelPhrase(spExp, uiAbsoluteOffset, spData->uiPhraseLength, spPhrase);
1975  spPhrase->uiNext = APG_UNDEFINED;
1976  spRule->uiPhraseCount++;
1977  if(spRule->uiFirstPhrase == APG_UNDEFINED){
1978  // first phrase for this rule
1979  spRule->uiFirstPhrase = uiPhraseIndex;
1980  }else{
1981  // link it to the last phrase for this rule
1982  spLastPhrase = (phrase_r*)vpVecAt(spExp->vpVecRelPhrases, spRule->uiLastPhrase);
1983  if(!spLastPhrase){
1984  XTHROW(spExp->spException, "rule phrases malfunction: last phrase is not in the list");
1985  }
1986  spLastPhrase->uiNext = uiPhraseIndex;
1987  }
1988  spRule->uiLastPhrase = uiPhraseIndex;
1989  }
1990  }
1991  return ID_AST_OK;
1992 }
1993 
1994 //static void pfnRuleCallback(callback_data* spData){
1995 // /*
1996 // * Note: callback_data acpString, uiStringLength and uiParserOffset refer to the sub-string being parser.
1997 // */
1998 // if(spData->uiParserState == ID_MATCH){
1999 // apgex* spExp = (apgex*)spData->vpUserData;
2000 // phrase_r* spLastPhrase;
2001 // rule_r* spRule = &spExp->spRelRules[spData->uiRuleIndex];
2002 // if(spRule->bEnabled){
2003 // // push this phrase on the list
2004 // aint uiPhraseIndex = uiVecLen(spExp->vpVecRelPhrases);
2005 // phrase_r* spPhrase = (phrase_r*)vpVecPush(spExp->vpVecRelPhrases, NULL);
2006 // aint uiAbsoluteOffset = spExp->uiLastIndex + spData->uiParserOffset;
2007 // vMakeRelPhrase(spExp, uiAbsoluteOffset, spData->uiParserPhraseLength, spPhrase);
2008 // spPhrase->uiNext = APG_UNDEFINED;
2009 // spRule->uiPhraseCount++;
2010 // if(spRule->uiFirstPhrase == APG_UNDEFINED){
2011 // // first phrase for this rule
2012 // spRule->uiFirstPhrase = uiPhraseIndex;
2013 // }else{
2014 // // link it to the last phrase for this rule
2015 // spLastPhrase = (phrase_r*)vpVecAt(spExp->vpVecRelPhrases, spRule->uiLastPhrase);
2016 // if(!spLastPhrase){
2017 // XTHROW(spExp->spException, "rule phrases malfunction: last phrase is not in the list");
2018 // }
2019 // spLastPhrase->uiNext = uiPhraseIndex;
2020 // }
2021 // spRule->uiLastPhrase = uiPhraseIndex;
2022 // }
2023 // }
2024 //}
2025 //
2026 static aint pfnUdtCallback(ast_data* spData){
2027  if(spData->uiState == ID_AST_PRE){
2028  apgex* spExp = (apgex*)spData->vpUserData;
2029  phrase_r* spLastPhrase;
2030  udt_r* spUdt = &spExp->spRelUdts[spData->uiIndex];
2031  if(spUdt->bEnabled){
2032  // push this phrase on the list
2033  aint uiPhraseIndex = uiVecLen(spExp->vpVecRelPhrases);
2034  phrase_r* spPhrase = (phrase_r*)vpVecPush(spExp->vpVecRelPhrases, NULL);
2035  aint uiAbsoluteOffset = spData->uiPhraseOffset;
2036  vMakeRelPhrase(spExp, uiAbsoluteOffset, spData->uiPhraseLength, spPhrase);
2037  spPhrase->uiNext = APG_UNDEFINED;
2038  spUdt->uiPhraseCount++;
2039  if(spUdt->uiFirstPhrase == APG_UNDEFINED){
2040  // first phrase for this rule
2041  spUdt->uiFirstPhrase = uiPhraseIndex;
2042  }else{
2043  // link it to the last phrase for this rule
2044  spLastPhrase = (phrase_r*)vpVecAt(spExp->vpVecRelPhrases, spUdt->uiLastPhrase);
2045  if(!spLastPhrase){
2046  XTHROW(spExp->spException, "UDT phrases malfunction: last phrase is not in the list");
2047  }
2048  spLastPhrase->uiNext = uiPhraseIndex;
2049  }
2050  spUdt->uiLastPhrase = uiPhraseIndex;
2051  }
2052  }
2053  return ID_AST_OK;
2054 }
2055 
2056 //static void pfnUdtCallback(callback_data* spData){
2057 // if(spData->uiParserState == ID_ACTIVE){
2058 // apgex* spExp = (apgex*)spData->vpUserData;
2059 // phrase_r* spLastPhrase;
2060 // udt_r* spUdt = &spExp->spRelUdts[spData->uiUDTIndex];
2061 // spUdt->pfnUdt(spData);
2062 // if(spUdt->bEnabled && spData->uiCallbackState == ID_MATCH){
2063 // // push this phrase on the list
2064 // aint uiPhraseIndex = uiVecLen(spExp->vpVecRelPhrases);
2065 // phrase_r* spPhrase = (phrase_r*)vpVecPush(spExp->vpVecRelPhrases, NULL);
2066 // aint uiAbsoluteOffset = spExp->uiLastIndex + spData->uiParserOffset;
2067 // vMakeRelPhrase(spExp, uiAbsoluteOffset, spData->uiCallbackPhraseLength, spPhrase);
2068 // spPhrase->uiNext = APG_UNDEFINED;
2069 // spUdt->uiPhraseCount++;
2070 // if(spUdt->uiFirstPhrase == APG_UNDEFINED){
2071 // // first phrase for this rule
2072 // spUdt->uiFirstPhrase = uiPhraseIndex;
2073 // }else{
2074 // // link it to the last phrase for this rule
2075 // spLastPhrase = (phrase_r*)vpVecAt(spExp->vpVecRelPhrases, spUdt->uiLastPhrase);
2076 // if(!spLastPhrase){
2077 // XTHROW(spExp->spException, "UDT phrases malfunction: last phrase is not in the list");
2078 // }
2079 // spLastPhrase->uiNext = uiPhraseIndex;
2080 // }
2081 // spUdt->uiLastPhrase = uiPhraseIndex;
2082 // }
2083 // }
2084 //}
2085 
2086 static void vClearForParse(apgex* spExp){
2087  spExp->uiNodeHits = 0;
2088  spExp->uiTreeDepth = 0;
2089  vVecClear(spExp->vpVecStrings);
2090  vVecClear(spExp->vpVecSource);
2092  vVecClear(spExp->vpVecPhrases);
2093  vVecClear(spExp->vpVecRelPhrases);
2094  vVecClear(spExp->vpVecRules);
2095  vVecClear(spExp->vpVecUdts);
2096  vVecClear(spExp->vpVecSource);
2097  vVecClear(spExp->vpVecReplaceRaw);
2098  vVecClear(spExp->vpVecReplacement);
2099  vVecClear(spExp->vpVecSplitPhrases);
2100  spExp->bReplaceMode = APG_FALSE;
2101  spExp->spLastMatch = NULL;
2102  spExp->spLeftContext = NULL;
2103  spExp->spRightContext = NULL;
2104  aint ui;
2105  for(ui = 0; ui < spExp->uiRuleCount; ui++){
2106  spExp->spRelRules[ui].uiFirstPhrase = APG_UNDEFINED;
2107  spExp->spRelRules[ui].uiLastPhrase = APG_UNDEFINED;
2108  spExp->spRelRules[ui].uiPhraseCount = 0;
2109  }
2110  if(spExp->uiUdtCount){
2111  for(ui = 0; ui < spExp->uiUdtCount; ui++){
2112  spExp->spRelUdts[ui].uiFirstPhrase = APG_UNDEFINED;
2113  spExp->spRelUdts[ui].uiLastPhrase = APG_UNDEFINED;
2114  spExp->spRelUdts[ui].uiPhraseCount = 0;
2115  }
2116  }
2117 }
2118 static void vClearForPattern(apgex* spExp){
2119  vVecClear(spExp->vpVecStrings);
2120  vVecClear(spExp->vpVecSource);
2122  vVecClear(spExp->vpVecPattern);
2123  vVecClear(spExp->vpVecFlags);
2124  vVecClear(spExp->vpVecRules);
2125  vVecClear(spExp->vpVecUdts);
2126  vVecClear(spExp->vpVecPhrases);
2127  vVecClear(spExp->vpVecRelPhrases);
2128  vVecClear(spExp->vpVecRelRules);
2129  vVecClear(spExp->vpVecRelUdts);
2130  vVecClear(spExp->vpVecReplaceRaw);
2131  vVecClear(spExp->vpVecReplacement);
2132  vVecClear(spExp->vpVecSplitPhrases);
2133  if(spExp->spDisplay && (spExp->spDisplay != stdout)){
2134  fclose(spExp->spDisplay);
2135  spExp->spDisplay = NULL;
2136  }
2137  if(spExp->vpExternalParser){
2138  // destroy the AST and trace objects, if any, but leave the user's external parser intact
2139  vAstDtor(spExp->vpAst);
2140  vTraceDtor(spExp->vpTrace);
2141  }else{
2142  // destroy the local parser which calls destructors for vpTrace & vpAst
2143  vParserDtor(spExp->vpParser);
2144  }
2145  spExp->vpParser = NULL;
2146  spExp->vpExternalParser = NULL;
2147  spExp->vpAst = NULL;
2148  spExp->vpTrace = NULL;
2149  spExp->spLastMatch = NULL;
2150  spExp->spLeftContext = NULL;
2151  spExp->spRightContext = NULL;
2152  spExp->spRelRules = NULL;
2153  spExp->spRelUdts = NULL;
2154  spExp->uiRuleCount = 0;
2155  spExp->uiUdtCount = 0;
2156  spExp->uiEnabledRuleCount = 0;
2157  spExp->uiEnabledUdtCount = 0;
2158  spExp->uiLastIndex = 0;
2159  spExp->uiNodeHits = 0;
2160  spExp->uiTreeDepth = 0;
2161  spExp->bDefaultMode = APG_TRUE;
2162  spExp->bTraceMode = APG_FALSE;
2163  spExp->bTraceHtmlMode = APG_FALSE;
2164  spExp->bGlobalMode = APG_FALSE;
2165  spExp->bPpptMode = APG_FALSE;
2166  spExp->bStickyMode = APG_FALSE;
2167  spExp->bReplaceMode = APG_FALSE;
2168 }
2169 
2170 static rule_r* spFindRule(apgex* spExp, const char* cpName){
2171  if(!spExp->vpParser || !spExp->uiRuleCount){
2172  XTHROW(spExp->spException, "no rules defined - vApgexPattern() or vApgexParser() must preceed this call");
2173  }
2174  if(!cpName || !cpName[0]){
2175  XTHROW(spExp->spException, "name cannot be NULL or empty");
2176  }
2177  // linear search for now
2178  aint ui;
2179  for(ui = 0; ui < spExp->uiRuleCount; ui++){
2180  if(iStriCmp(spExp->spRelRules[ui].cpRuleName, cpName) == 0){
2181  return &spExp->spRelRules[ui];
2182  }
2183  }
2184  return NULL;
2185 }
2186 
2187 static udt_r* spFindUdt(apgex* spExp, const char* cpName){
2188  if(!spExp->vpParser || !spExp->uiRuleCount){
2189  XTHROW(spExp->spException, "no rules defined - vApgexPattern() or vApgexParser() must preceed this call");
2190  }
2191  if(!cpName || !cpName[0]){
2192  XTHROW(spExp->spException, "name cannot be NULL or empty");
2193  }
2194  // linear search for now
2195  aint ui;
2196  for(ui = 0; ui < spExp->uiUdtCount; ui++){
2197  if(iStriCmp(spExp->spRelUdts[ui].cpUdtName, cpName) == 0){
2198  return &spExp->spRelUdts[ui];
2199  }
2200  }
2201  return NULL;
2202 }
2203 
2204 static abool bIsNameChar(char cChar){
2205  if(cChar >= 65 && cChar <= 90){ // upper case
2206  return APG_TRUE;
2207  }
2208  if(cChar >= 97 && cChar <= 122){ // lower case
2209  return APG_TRUE;
2210  }
2211  if(cChar == 45){ // hyphen "-"
2212  return APG_TRUE;
2213  }
2214  if(cChar == 95){ // underscore "_" (required in UDT names)
2215  return APG_TRUE;
2216  }
2217  return APG_FALSE;
2218 }
2219 
udt_r::pfnUdt
parser_callback pfnUdt
The UDT callback, if this is a UDT. Cannot be NULL;.
Definition: apgex.c:89
apgex_result::uiNodeHits
aint uiNodeHits
The number of parser node hits.
Definition: apgex.h:83
apgex::vpVecPattern
void * vpVecPattern
Vector for the pattern string, if any.
Definition: apgex.c:119
phrase_r
For internal object use only. Defines a phrase as an offset into vpVecRelPhases.
Definition: apgex.c:57
apgex_rule::spPhrases
apgex_phrase * spPhrases
The list of matched phrases. Any given rule or UDT may have multiple matched sub-phrases.
Definition: apgex.h:60
apgex::vpVecFlags
void * vpVecFlags
Vector for the input flags string.
Definition: apgex.c:120
parser_config::bParseSubString
abool bParseSubString
If true (non-zero), only parse the defined sub-string of the input string.
Definition: parser.h:202
TRACE_APGEX_CHECK
#define TRACE_APGEX_CHECK(x)
Definition: apgex.c:209
APG_INFINITE
#define APG_INFINITE
Definition: apg.h:320
vUtilFileRead
void vUtilFileRead(void *vpMem, const char *cpFileName, uint8_t *ucpData, aint *uipLen)
Read a file into the caller's data area.
Definition: utilities.c:252
parser_config::uiSubStringBeg
aint uiSubStringBeg
The first character of the sub-string to parse. Must be < uiInputLength or exception is thrown.
Definition: parser.h:203
apgex::vpVecSplitPhrases
void * vpVecSplitPhrases
Vector for the resulting phrases of spApgexSplit().
Definition: apgex.c:130
TRACE_APGEX_FOOTER
#define TRACE_APGEX_FOOTER(t)
Definition: apgex.c:207
apgex_rule::uiPhraseCount
aint uiPhraseCount
The number of matched sub-phrases for this rule/UDT.
Definition: apgex.h:61
sApgexReplace
apg_phrase sApgexReplace(void *vpCtx, apg_phrase *spSource, apg_phrase *spReplacement)
Replace the matched phrase with a specified phrase.
Definition: apgex.c:528
apgex::bTraceMode
abool bTraceMode
True if tracing is requested.
Definition: apgex.c:152
vMemDtor
void vMemDtor(void *vpCtx)
Destroys a Memory component. Frees all memory allocated.
Definition: memory.c:141
apgex::bTraceHtmlMode
abool bTraceHtmlMode
True if tracing in HTML mode is requested.
Definition: apgex.c:153
apgex::vpParser
void * vpParser
Pointer to the SABNF grammar parser.
Definition: apgex.c:131
vApgexPatternFile
void vApgexPatternFile(void *vpCtx, const char *cpFileName, const char *cpFlags)
Reads the SABNF grammar defining the pattern from a file.
Definition: apgex.c:404
apgex_properties::bTraceMode
abool bTraceMode
True if the t flag is set in the cpFlags string.
Definition: apgex.h:114
ast_data::uiPhraseOffset
aint uiPhraseOffset
Definition: ast.h:72
apgex::spLeftContext
apgex_phrase * spLeftContext
Pointer to the left context of the last result.
Definition: apgex.c:139
apgex::vpVecRelRules
void * vpVecRelRules
Vector of relative rules.
Definition: apgex.c:126
apgex::uiNodeHits
aint uiNodeHits
Number of node hits in the pattern-matching parse.
Definition: apgex.c:148
apgex_properties
Detailed information about the apgex object after vApgexPattern() has been called.
Definition: apgex.h:94
vApiInClear
void vApiInClear(void *vpCtx)
Clears the input and related memory.
Definition: input.c:61
vAstSetRuleCallback
void vAstSetRuleCallback(void *vpCtx, aint uiRuleIndex, ast_callback pfnCallback)
Define a callback function for a single rule on the AST.
Definition: ast.c:243
apgex::vpApi
void * vpApi
Pointer to the API object used to generate the parser.
Definition: apgex.c:132
vApgexDefineUDT
void vApgexDefineUDT(void *vpCtx, const char *cpName, parser_callback pfnUdt)
Define the callback function for a User-Defined Terminal (UDT).
Definition: apgex.c:1222
apgex_properties::sRightContext
apgex_phrase sRightContext
The right context of the last match - that is the phrase suffix to the matched phrase.
Definition: apgex.h:107
sApgexExec
apgex_result sApgexExec(void *vpCtx, apg_phrase *spSource)
Attempt a pattern match on the source array of APG alphabet characters.
Definition: apgex.c:479
BUF_SIZE
#define BUF_SIZE
Definition: apgex.c:44
parser_config::acpInput
const achar * acpInput
Pointer to the input string.
Definition: parser.h:199
result_r::spUdts
udt_r * spUdts
Definition: apgex.c:106
vpApiCtor
void * vpApiCtor(exception *spEx)
Construct an API component context (object).
Definition: api.c:55
cpFmtFirstBytes
const char * cpFmtFirstBytes(void *vpCtx, const uint8_t *ucpBytes, uint64_t uiLength, int iStyle, uint64_t uiOffset, uint64_t uiLimit)
Initiate the iterator over an array of 8-bit byte data.
Definition: format.c:210
ACCENT
#define ACCENT
Definition: apgex.c:47
rule_r::uiPhraseCount
aint uiPhraseCount
The number of matched phrases.
Definition: apgex.c:71
apgex::bReplaceMode
abool bReplaceMode
True if in replace mode.
Definition: apgex.c:150
APOS
#define APOS
Definition: apgex.c:48
rule_r::bEnabled
abool bEnabled
True if this rule has been enabled for phrase capture.
Definition: apgex.c:76
apgex_properties::bStickyMode
abool bStickyMode
True if the y flag is set prior to any occurrence of g in the cpFlags string.
Definition: apgex.h:113
apgex::spRelUdts
udt_r * spRelUdts
Pointer to the relative UDTs in the vector of relative UDTs.
Definition: apgex.c:142
vApiInValidate
void vApiInValidate(void *vpCtx, abool bStrict)
Scans the input SABNF grammar for invalid characters and line ends.
Definition: input.c:204
ID_AST_OK
#define ID_AST_OK
normal AST callback function return
Definition: parser.h:93
vExContext
void vExContext()
Handles bad context pointers.
Definition: exception.c:126
ID_AST_PRE
#define ID_AST_PRE
indicates pre-node-traversal AST callback state (down the tree)
Definition: parser.h:91
parser_config::vpUserData
void * vpUserData
Pointer to user data, if any. Not examined or used by the parser in any way. Presented to the user's ...
Definition: parser.h:210
vApiOpcodes
void vApiOpcodes(void *vpCtx)
Parse the SABNF grammar and translate its AST into opcodes for all the rules.
Definition: semantics.c:64
ast_data
Input data to the AST callback functions.
Definition: ast.h:69
apgex_result::uiTreeDepth
aint uiTreeDepth
The maximum parsing tree depth.
Definition: apgex.h:84
achar
uint_fast8_t achar
achar is the type for the parser's alphabet characters.
Definition: apg.h:91
bIsPhraseAscii
abool bIsPhraseAscii(apg_phrase *spPhrase)
Determine if a phrase consists entirely of printable ASCII characters.
Definition: tools.c:287
apgex::vpVecUdts
void * vpVecUdts
Vector of UDT structures.
Definition: apgex.c:122
vApgexPattern
void vApgexPattern(void *vpCtx, const char *cpPattern, const char *cpFlags)
Prepare a phrase-matching parser for the given pattern.
Definition: apgex.c:378
apgex_result
The phrase matching results.
Definition: apgex.h:72
FMT_CANONICAL
#define FMT_CANONICAL
Display lines with both FMT_HEX and FMT_ASCII formats.
Definition: format.h:55
apgex_properties::sLastMatch
apgex_phrase sLastMatch
The last-matched phrase. Same as spResult from the last call to sApgexExec().
Definition: apgex.h:104
udt_r::cpUdtName
const char * cpUdtName
UDT name.
Definition: apgex.c:88
apgex::vpFmt
void * vpFmt
Pointer to a format object used for display.
Definition: apgex.c:133
vAstTranslate
void vAstTranslate(void *vpCtx, void *vpUserData)
Do a depth-first traversal of the AST with user-defined callback functions to translate the AST recor...
Definition: ast.c:165
iStriCmp
int iStriCmp(const char *cpLeft, const char *cpRight)
Compare two strings. A case-insensitive version of strcmp().
Definition: tools.c:53
apgex::bGlobalMode
abool bGlobalMode
True if in global mode.
Definition: apgex.c:154
cpFmtNext
const char * cpFmtNext(void *vpCtx)
Formats the next line of data.
Definition: format.c:386
apgex_properties::vpParser
void * vpParser
Pointer to the parser object context.
Definition: apgex.h:95
vApiDtor
void vApiDtor(void *vpCtx)
The API component destructor.
Definition: api.c:84
apgex::vpVecStrings
void * vpVecStrings
Vector for string scratch space.
Definition: apgex.c:123
vpApiGetErrorLog
void * vpApiGetErrorLog(void *vpCtx)
Get the internal message log.
Definition: api.c:117
rule_r::uiRuleIndex
aint uiRuleIndex
Rule index or index.
Definition: apgex.c:70
ast_data::uiPhraseLength
aint uiPhraseLength
Definition: ast.h:73
apgex_rule::uiIndex
aint uiIndex
The rule or UDT grammar index.
Definition: apgex.h:62
rule_r::uiFirstPhrase
aint uiFirstPhrase
Offset in vpVecRelPhases for the first phrase of a singly-linked list of phrases matched by this rule...
Definition: apgex.c:72
apgex_properties::bDefaultMode
abool bDefaultMode
True if the cpFlags parameter in vApgexPattern() is NULL or empty.
Definition: apgex.h:110
vpVecAt
void * vpVecAt(void *vpCtx, aint uiIndex)
Get a the indexed vector element. The vector is not altered.
Definition: vector.c:362
apgex::vpVecPhrases
void * vpVecPhrases
Vector of matched phrases.
Definition: apgex.c:124
apgex_properties::cpFlags
const char * cpFlags
The original string of flags from vApgexPattern().
Definition: apgex.h:98
ast_data::uiIndex
aint uiIndex
Index of the rule or UDT.
Definition: ast.h:76
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
apgex_result::spLeftContext
apgex_phrase * spLeftContext
The phrase prefix.
Definition: apgex.h:74
vTraceDtor
void vTraceDtor(void *vpCtx)
Trace destructor.
Definition: trace.c:152
phrase_r::uiLength
aint uiLength
The length or number of characters in the phrase.
Definition: apgex.c:59
vParserSetUdtCallback
void vParserSetUdtCallback(void *vpCtx, aint uiUdtId, parser_callback pfnCallback)
Set a call back function for a specific UDT.
Definition: parser.c:407
apgex_result::uiRuleCount
aint uiRuleCount
The number of combined rules and UDTs in the pattern.
Definition: apgex.h:82
aint
uint_fast32_t aint
The APG parser's unsigned integer type.
Definition: apg.h:79
parser_config::uiInputLength
aint uiInputLength
Number of input string alphabet characters.
Definition: parser.h:200
apgex::vpTrace
void * vpTrace
Pointer to the trace object if any.
Definition: apgex.c:135
vpTraceCtor
void * vpTraceCtor(void *vpCtx)
The trace object constructor.
Definition: trace.c:92
parser_config
Defines the input string and other configuration parameters for the parser,.
Definition: parser.h:198
apgex_result::spResult
apgex_phrase * spResult
The matched phrase. NULL if no match.
Definition: apgex.h:73
vAstDtor
void vAstDtor(void *vpCtx)
Definition: ast.c:81
apgex_properties::uiLastIndex
aint uiLastIndex
The index of the character in the input string where the attempted pattern match begins....
Definition: apgex.h:108
apgex::vpVecRelPhrases
void * vpVecRelPhrases
Vector of relative phrases - offsets rather than absolute pointers.
Definition: apgex.c:125
rule_r::cpRuleName
const char * cpRuleName
Rule name.
Definition: apgex.c:69
apgex::uiUdtCount
aint uiUdtCount
Number of UDTs in the SABNF pattern grammar.
Definition: apgex.c:144
BKR_APGEX_CHECK
#define BKR_APGEX_CHECK(e)
Definition: apg.h:213
apgex::vpVecOriginalSource
void * vpVecOriginalSource
Vector to hold the original source with no replacements.
Definition: apgex.c:118
vpMemAlloc
void * vpMemAlloc(void *vpCtx, aint uiBytes)
Allocates memory.
Definition: memory.c:196
pfn_replace
apg_phrase(* pfn_replace)(apgex_result *spResult, apgex_properties *spProperties, void *vpUser)
Prototype for the replacement function used by sApgexReplaceFunc().
Definition: apgex.h:125
apgex::uiLastIndex
aint uiLastIndex
Last index - the offset to the first character to begin the search for a pattern match.
Definition: apgex.c:147
apgex::uiRuleCount
aint uiRuleCount
Number of rules in the SABNF pattern grammar.
Definition: apgex.c:143
apgex::vpMem
void * vpMem
Pointer to a memory object used for all memory allocations.
Definition: apgex.c:116
result_r::spLeftContext
phrase_r * spLeftContext
Definition: apgex.c:103
apgex::vpValidate
const void * vpValidate
Must be the "magic number" to be a valid context.
Definition: apgex.c:113
uiVecLen
aint uiVecLen(void *vpCtx)
Get the vector length. That is, the number of elements on the vector.
Definition: vector.c:385
vApiSyntax
void vApiSyntax(void *vpCtx, abool bStrict)
Parse the SABNF grammar to validate that the grammar structure is valid.
Definition: syntax.c:51
vpVecCtor
void * vpVecCtor(void *vpMem, aint uiElementSize, aint uiInitialAlloc)
The vector object constructor.
Definition: vector.c:118
vpApgexCtor
void * vpApgexCtor(exception *spEx)
The phrase-matching engine object constructor.
Definition: apgex.c:239
ast_data::uiState
aint uiState
Definition: ast.h:74
parser_state
The parser's final state.
Definition: parser.h:183
udt_r::uiFirstPhrase
aint uiFirstPhrase
Offset in vpVecRelPhases for the first phrase match for this rule.
Definition: apgex.c:93
result_r::spResult
phrase_r * spResult
Definition: apgex.c:102
apgex::spRightContext
apgex_phrase * spRightContext
Pointer to the right context of the last result.
Definition: apgex.c:140
apgex::bPpptMode
abool bPpptMode
True if PPPTs are used.
Definition: apgex.c:155
apgex.h
Header file for the apgex object.
exception
A structure to describe the type and location of a caught exception.
Definition: exception.h:47
apgex_result::uiLastIndex
aint uiLastIndex
The last index following the last pattern match attempt.
Definition: apgex.h:81
apg_phrase
Defines a pointer to an achar array plus its length. That is, a phrase as is often used by APG.
Definition: lib.h:60
vMemFree
void vMemFree(void *vpCtx, const void *vpData)
Free memory previously allocated with vpMemAlloc().
Definition: memory.c:226
TRACE_DTOR
#define TRACE_DTOR(x)
Definition: apg.h:171
vpApgexGetParser
void * vpApgexGetParser(void *vpCtx)
Get a pointer to the parser object's context.
Definition: apgex.c:1009
apgex_rule::cpRuleName
const char * cpRuleName
The rule or UDT name.
Definition: apgex.h:59
apgex::vpVecReplaceRaw
void * vpVecReplaceRaw
Vector for the original replacement string with no modifications.
Definition: apgex.c:128
apgex_properties::bTraceHtmlMode
abool bTraceHtmlMode
True if the th flags ar set for HTML trace output in the cpFlags string.
Definition: apgex.h:115
apgex::spDisplay
FILE * spDisplay
The open file for display - may be stdout.
Definition: apgex.c:137
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
vpApiOutputParser
void * vpApiOutputParser(void *vpCtx)
Generate a parser object directly from the specified SABNF grammar.
Definition: output.c:217
vpApgexGetTrace
void * vpApgexGetTrace(void *vpCtx)
Get a pointer to the trace object's context.
Definition: apgex.c:984
apgex::vpExternalParser
void * vpExternalParser
Pointer to the externally-supplied parsed, if any.
Definition: apgex.c:136
apgex_properties::sLastSource
apg_phrase sLastSource
The last source or input string as a phrase - may be different from original if sApgexReplace() or sA...
Definition: apgex.h:102
apgex::uiTreeDepth
aint uiTreeDepth
Maximum tree depth reached in the pattern-matching parse.
Definition: apgex.c:149
cpMsgsFirst
const char * cpMsgsFirst(void *vpCtx)
Get a pointer to the first logged message, if any.
Definition: msglog.c:164
cpMsgsNext
const char * cpMsgsNext(void *vpCtx)
Get a pointer to the next logged message, if any.
Definition: msglog.c:185
APG_UNDEFINED
#define APG_UNDEFINED
Definition: apg.h:318
bExValidate
abool bExValidate(exception *spException)
Test an exception structure for validity.
Definition: exception.c:70
phrase_r::uiSourceOffset
aint uiSourceOffset
Offset into the source array for the first character of the phrase.
Definition: apgex.c:58
vApgexDisplayPhrase
void vApgexDisplayPhrase(void *vpCtx, apgex_phrase *spPhrase, const char *cpFileName)
Display the object's properties.
Definition: apgex.c:1098
vApgexDisplayResult
void vApgexDisplayResult(void *vpCtx, apgex_result *spResult, const char *cpFileName)
Display the complete results from a pattern match.
Definition: apgex.c:1129
vApgexDisplayProperties
void vApgexDisplayProperties(void *vpCtx, apgex_properties *spProperties, const char *cpFileName)
Display the object's properties.
Definition: apgex.c:1028
bApiAttrs
abool bApiAttrs(void *vpCtx)
Computes the grammar's attributes.
Definition: attributes.c:79
vpVecFirst
void * vpVecFirst(void *vpCtx)
Get the first element one the vector. The vector is not altered.
Definition: vector.c:326
spApgexSplit
apg_phrase * spApgexSplit(void *vpCtx, apg_phrase *spSource, aint uiLimit, aint *uipCount)
Split a phrase into an array of sub-phrases.
Definition: apgex.c:648
vpVecPushn
void * vpVecPushn(void *vpCtx, void *vpElement, aint uiCount)
Adds one or more elements to the end of the array.
Definition: vector.c:221
vpMemCtor
void * vpMemCtor(exception *spException)
Construct a memory component.
Definition: memory.c:121
apgex::vpVecReplacement
void * vpVecReplacement
Vector for the final form of the replacement string.
Definition: apgex.c:129
parser_state::uiState
aint uiState
One of ID_EMPTY, ID_MATCH or ID_NOMATCH. Note that it is possible for the parser to match a phrase wi...
Definition: parser.h:185
udt_r::uiUdtIndex
aint uiUdtIndex
Rule or UDT index or index.
Definition: apgex.c:91
apgex::bDefaultMode
abool bDefaultMode
True if in default mode.
Definition: apgex.c:151
bIsBigEndian
abool bIsBigEndian(void)
Determine if the current machine uses big endian word storage.
Definition: tools.c:96
TRACE_HEADER_APGEX
#define TRACE_HEADER_APGEX
Identifies apgex as the header handler.
Definition: tracep.h:50
TRACE_APGEX_OUTPUT
#define TRACE_APGEX_OUTPUT(x)
Definition: apgex.c:210
apgex_properties::cpPattern
const char * cpPattern
Internally preserve copy of the SABNF grammar defining the string to match. NULL if the pattern is de...
Definition: apgex.h:99
apgex::uiEnabledRuleCount
aint uiEnabledRuleCount
Number of enabled rules.
Definition: apgex.c:145
APG_TRUE
#define APG_TRUE
Definition: apg.h:291
rule_r::uiLastPhrase
aint uiLastPhrase
Offset into vpVecRelPhrases for the last matched phrase. APG_UNDEFINED if no phrases for this rule ex...
Definition: apgex.c:74
vTraceApgexType
void vTraceApgexType(void *vpCtx, aint uiType)
Called only by apgex. Sets the display type for apgex tracing.
Definition: trace-config.c:116
result_r
For internal object use only. The phrase matching result in relative phrases.
Definition: apgex.c:101
vpAstCtor
void * vpAstCtor(void *vpParserCtx)
The AST object constructor.
Definition: ast.c:51
apgex::bStickyMode
abool bStickyMode
True if in sticky mode.
Definition: apgex.c:156
apgex_properties::sOriginalSource
apg_phrase sOriginalSource
The original source or input string as a phrase.
Definition: apgex.h:101
apgex_properties::bGlobalMode
abool bGlobalMode
True if the g flag is set prior to any occurrence of y in the cpFlags string.
Definition: apgex.h:111
rule_r
For internal object use only. Relative offsets to phrase information for rules.
Definition: apgex.c:68
cpApiInString
const char * cpApiInString(void *vpCtx, const char *cpString)
Reads an SABNF grammar byte stream from a string.
Definition: input.c:165
apg_phrase::uiLength
aint uiLength
The number of characters in the array.
Definition: lib.h:62
apgex_result::spRightContext
apgex_phrase * spRightContext
The phrase suffix.
Definition: apgex.h:77
parser_state::uiMaxTreeDepth
aint uiMaxTreeDepth
The maximum tree depth reached during the parse.
Definition: parser.h:190
vApgexSetLastIndex
void vApgexSetLastIndex(void *vpCtx, aint uiLastIndex)
Sets the index of the character in the source where the pattern-match search is to begin.
Definition: apgex.c:874
result_r::spRules
rule_r * spRules
Definition: apgex.c:105
vParserDtor
void vParserDtor(void *vpCtx)
Clears the parser component's context and frees all heap memory associated with this parser.
Definition: parser.c:245
RANGLE
#define RANGLE
Definition: apgex.c:50
AMP
#define AMP
Definition: apgex.c:46
TRACE_APGEX_SEPARATOR
#define TRACE_APGEX_SEPARATOR(x)
Definition: apgex.c:208
UNDER
#define UNDER
Definition: apgex.c:51
ast_data::vpUserData
void * vpUserData
Definition: ast.h:80
udt_r::uiPhraseCount
aint uiPhraseCount
The number of matched phrases.
Definition: apgex.c:92
TRACE_HTML
#define TRACE_HTML
Identifier for HTML trace record format.
Definition: trace.h:45
APG_MAX_AINT
#define APG_MAX_AINT
Since the maximum unsigned integer value is used to indicate Infinite and Undefined values,...
Definition: apg.h:329
parser_state::uiHitCount
aint uiHitCount
The number of nodes visited during the traversal of the parse tree.
Definition: parser.h:191
apgex_properties::vpTrace
void * vpTrace
Pointer to the trace object context. NULL unless the t flag is used.
Definition: apgex.h:97
vApgexDisplayPatternErrors
void vApgexDisplayPatternErrors(void *vpCtx, const char *cpFileName)
Definition: apgex.c:1180
apgex
For internal object use only. The phrase matching object context.
Definition: apgex.c:112
vApgexDtor
void vApgexDtor(void *vpCtx)
The phrase-matching engine object destructor.
Definition: apgex.c:295
abool
uint8_t abool
abool is the APG bool type.
Definition: apg.h:140
result_r::spRightContext
phrase_r * spRightContext
Definition: apgex.c:104
parser_state::uiPhraseLength
aint uiPhraseLength
Length of the matched phrase.
Definition: parser.h:188
apgex::uiEnabledUdtCount
aint uiEnabledUdtCount
Number of enabled UDTs.
Definition: apgex.c:146
vpVecPopi
void * vpVecPopi(void *vpCtx, aint uiIndex)
Pops the element at the given zero-based index and all higher indexes.
Definition: vector.c:306
vApgexBkrCheck
void vApgexBkrCheck(exception *spEx)
Back referencing check.
Definition: apgex.c:279
udt_r::bEnabled
abool bEnabled
True if this UDT has been enabled for phrase capture.
Definition: apgex.c:95
apgex_rule
Information about each rule or UDT in the SABNF pattern.
Definition: apgex.h:58
DOLLAR
#define DOLLAR
Definition: apgex.c:45
vApgexEnableRules
void vApgexEnableRules(void *vpCtx, const char *cpNames, abool bEnable)
Enable or disable specified rule and/or UDT names for phrase capture.
Definition: apgex.c:786
apgex::vpVecSource
void * vpVecSource
Definition: apgex.c:117
vApgexPatternParser
void vApgexPatternParser(void *vpCtx, void *vpParser, const char *cpFlags)
Define the SABNF pattern with a user-created parser.
Definition: apgex.c:444
sApgexProperties
apgex_properties sApgexProperties(void *vpCtx)
Get a copy of the object's properties.
Definition: apgex.c:888
apgex::spLastMatch
apgex_phrase * spLastMatch
Pointer to the last matched result.
Definition: apgex.c:138
sApgexReplaceFunc
apg_phrase sApgexReplaceFunc(void *vpCtx, apg_phrase *spSource, pfn_replace pfnFunc, void *vpUser)
Replace the matched phrase with a user-generated phrase.
Definition: apgex.c:581
apgex::vpAst
void * vpAst
Pointer to the AST object if any.
Definition: apgex.c:134
vAstSetUdtCallback
void vAstSetUdtCallback(void *vpCtx, aint uiUdtIndex, ast_callback pfnCallback)
Define a callback function for a single UDT on the AST.
Definition: ast.c:266
apgex::vpVecRelUdts
void * vpVecRelUdts
Vector of relative UDTs.
Definition: apgex.c:127
apgex_properties::sLeftContext
apgex_phrase sLeftContext
The left context of the last match - that is the phrase prefix to the matched phrase.
Definition: apgex.h:106
apgex_phrase::sPhrase
apg_phrase sPhrase
The matched phrase.
Definition: apgex.h:46
vFmtDtor
void vFmtDtor(void *vpCtx)
The object destructor.
Definition: format.c:146
apgex_properties::vpAst
void * vpAst
Pointer to the AST object context. NULL unless the a flag is used.
Definition: apgex.h:96
apgex_properties::bPpptMode
abool bPpptMode
True if the p flag is set. The parser will use Partially-Predictive Parsing Tables.
Definition: apgex.h:112
bApgexTest
abool bApgexTest(void *vpCtx, apg_phrase *spSource)
Report only success or failure on a pattern match.
Definition: apgex.c:752
vpApgexGetAst
void * vpApgexGetAst(void *vpCtx)
Get a pointer to the AST object's context.
Definition: apgex.c:957
apgex_phrase
The representation of a matched phrase.
Definition: apgex.h:45
vTraceOutputType
void vTraceOutputType(void *vpCtx, aint uiType)
Set the trace record display type.
Definition: trace-config.c:90
apgex::vpVecRules
void * vpVecRules
Vector of rule structures.
Definition: apgex.c:121
vpFmtCtor
void * vpFmtCtor(exception *spEx)
The object constructor.
Definition: format.c:118
vpVecPush
void * vpVecPush(void *vpCtx, void *vpElement)
Adds one element to the end of the array.
Definition: vector.c:193
apgex_result::spRules
apgex_rule * spRules
The phrases matched by all enabled rules and/or UDTs. NULL if no match.
Definition: apgex.h:80
bParserValidate
abool bParserValidate(void *vpCtx)
Validate the context pointer of a parser.
Definition: parser.c:422
vVecClear
void vVecClear(void *vpCtx)
Clears all used elements in a vector component.
Definition: vector.c:420
apgex::spRelRules
rule_r * spRelRules
Pointer to the relative rules in the vector of relative rules.
Definition: apgex.c:141
udt_r::uiLastPhrase
aint uiLastPhrase
Index into vpVecRelPhrases for the next match or APG_UNDEFINED if this is the last block.
Definition: apgex.c:94
phrase_r::uiNext
aint uiNext
The index to the next phrase in a singly-linked list. APG_UNDEFINED marks last phrase in list.
Definition: apgex.c:60
apgex_phrase::uiPhraseOffset
aint uiPhraseOffset
Offset into the source string where the matched phrase begins.
Definition: apgex.h:47
apg_phrase::acpPhrase
const achar * acpPhrase
Pointer to an array of type achar APG alphabet characters.
Definition: lib.h:61
udt_r
For internal object use only. Relative offsets to phrase information for UDTs.
Definition: apgex.c:87
LANGLE
#define LANGLE
Definition: apgex.c:49
apgex::spException
exception * spException
Pointer to the exception structure for reporting errors to the application catch block.
Definition: apgex.c:114
bMsgsValidate
abool bMsgsValidate(void *vpCtx)
Validate a msglog context pointer.
Definition: msglog.c:110
TRACE_APGEX_HEADER
#define TRACE_APGEX_HEADER(t)
Definition: apgex.c:206
vApiPppt
void vApiPppt(void *vpCtx, char **cppProtectedRules, aint uiProtectedRules)
Compute the Partially-Predictive Parsing Tables.
Definition: pppt.c:101
APG_FALSE
#define APG_FALSE
Definition: apg.h:292
vParserParse
void vParserParse(void *vpCtx, parser_config *spConfig, parser_state *spState)
Parse an input string of alphabet characters.
Definition: parser.c:268
APG Version 7.0 is licensed under the 2-Clause BSD License,
an Open Source Initiative Approved License.