Version 7.0
Copyright © 2021 Lowell D. Thomas
APG
… an ABNF Parser Generator
main.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 * *************************************************************************************/
113 #include "../../api/api.h"
114 
115 static char* s_cpDescription =
116  "Example demonstrating the use and usefulness of the AST.";
117 
118 static char* s_cppCases[] = {
119  "Display application information.",
120  "Illustrate the rule call back function pitfall and solution with AST.",
121 };
122 static long int s_iCaseCount = (long int)(sizeof(s_cppCases) / sizeof(s_cppCases[0]));
123 
124 static int iHelp(void){
125  long int i = 0;
127  printf("description: %s\n", s_cpDescription);
128  printf(" usage: ex-trace [arg]\n");
129  printf(" arg = n, 1 <= n <= %ld\n", s_iCaseCount);
130  printf(" execute case number n\n");
131  printf(" arg = anything else, or nothing at all\n");
132  printf(" print this help screen\n");
133  printf("\n");
134  for(; i < s_iCaseCount; i++){
135  printf("case %ld %s\n", (i + 1), s_cppCases[i]);
136  }
137  return EXIT_SUCCESS;
138 }
139 
140 static int iApp() {
141  // print the current working directory
143  printf("\n");
144 
145  // display the current APG sizes and macros
146  vUtilApgInfo();
147  return EXIT_SUCCESS;
148 }
149 
150 typedef struct{
155 } my_data;
156 
157 static void vRuleA(callback_data* spData) {
158  if (spData->uiParserState == ID_MATCH) {
159  // increment the A node count
160  my_data* spMyData = (my_data*)spData->vpUserData;
161  spMyData->uiCountA++;
162  }
163 }
164 static void vRuleB(callback_data* spData) {
165  if (spData->uiParserState == ID_MATCH) {
166  // increment the A node count
167  my_data* spMyData = (my_data*)spData->vpUserData;
168  spMyData->uiCountB++;
169  }
170 }
171 static void vRuleC(callback_data* spData) {
172  if (spData->uiParserState == ID_MATCH) {
173  // increment the A node count
174  my_data* spMyData = (my_data*)spData->vpUserData;
175  spMyData->uiCountC++;
176  }
177 }
178 static aint uiAstA(ast_data* spData) {
179  if (spData->uiState == ID_AST_POST) {
180  // increment the A node count
181  my_data* spMyData = (my_data*)spData->vpUserData;
182  spMyData->uiCountA++;
183  }
184  return ID_AST_OK;
185 }
186 static aint uiAstB(ast_data* spData) {
187  if (spData->uiState == ID_AST_POST) {
188  // increment the A node count
189  my_data* spMyData = (my_data*)spData->vpUserData;
190  spMyData->uiCountB++;
191  }
192  return ID_AST_OK;
193 }
194 static aint uiAstC(ast_data* spData) {
195  if (spData->uiState == ID_AST_POST) {
196  // increment the A node count
197  my_data* spMyData = (my_data*)spData->vpUserData;
198  spMyData->uiCountC++;
199  }
200  return ID_AST_OK;
201 }
202 static int iAst() {
203  int iReturn = EXIT_SUCCESS;
204  static void* vpApi = NULL;
205  static void* vpAst = NULL;
206  static void* vpMem = NULL;
207  static void* vpParser = NULL;
208  char* cpGrammar = "S = (1*A 1*B) / (1*A 1*C)\n"
209  "A = \"a\"\n"
210  "B = \"b\"\n"
211  "C = \"c\"\n";
212  char* cpInput = "aaaacc";
213  parser_config sConfig;
214  parser_state sState;
215  apg_phrase* spPhrase;
216  my_data sMyData = {};
217  exception e;
218  XCTOR(e);
219  if(e.try){
220  // try block - construct the API object
221  vpApi = vpApiCtor(&e);
222 
223  // convert the input string to alphabet characters (in general, sizeof(achar) != sizeof(char))
224  vpMem = vpMemCtor(&e);
225  spPhrase = spUtilStrToPhrase(vpMem, cpInput);
226  memset(&sMyData, 0, sizeof(sMyData));
227  sMyData.spException = &e;
228 
229  // construct a simple parser without PPPT
230  vApiString(vpApi, cpGrammar, APG_FALSE, APG_FALSE);
231  vpParser = vpApiOutputParser(vpApi);
232  vpAst = vpAstCtor(vpParser);
233 
234  // the parser call back functions
235  vParserSetRuleCallback(vpParser, uiParserRuleLookup(vpParser, "A" ), vRuleA);
236  vParserSetRuleCallback(vpParser, uiParserRuleLookup(vpParser, "B" ), vRuleB);
237  vParserSetRuleCallback(vpParser, uiParserRuleLookup(vpParser, "C" ), vRuleC);
238 
239  // the AST call back functions
240  vAstSetRuleCallback(vpAst, uiParserRuleLookup(vpParser, "A" ), uiAstA);
241  vAstSetRuleCallback(vpAst, uiParserRuleLookup(vpParser, "B" ), uiAstB);
242  vAstSetRuleCallback(vpAst, uiParserRuleLookup(vpParser, "C" ), uiAstC);
243 
244  // count the number of successful visits to the A node.
245  printf("\nThe parsing problem: count the occurrences of A in the input string.\n");
246  printf(" the parser, without built-in protection against failed branches, counts the As twice\n");
247  printf(" generating and translating an AST solves the problem\n");
248  memset(&sConfig, 0, sizeof(sConfig));
249  sConfig.acpInput = spPhrase->acpPhrase;
250  sConfig.uiInputLength = spPhrase->uiLength;
251  sConfig.uiStartRule = 0;
252  sConfig.vpUserData = (void*)&sMyData;
253 // vpTraceCtor(vpParser, NULL);
254  vParserParse(vpParser, &sConfig, &sState);
255 
256  // display the input string
257  printf("\nThe Input String\n");
258  printf("input string: %s\n", cpInput);
259 
260  // display the state without PPPT
261  printf("\nParser State without PPPT\n");
262  vUtilPrintParserState(&sState);
263 
264  // display the matched parser rule counts
265  printf("\nMatched Rule Counts from Parser (notice the A rules get counted twice)\n");
266  printf("A: %"PRIuMAX"\n", (luint)sMyData.uiCountA);
267  printf("B: %"PRIuMAX"\n", (luint)sMyData.uiCountB);
268  printf("C: %"PRIuMAX"\n", (luint)sMyData.uiCountC);
269 
270  // translate the AST
271  memset(&sMyData, 0, sizeof(sMyData));
272  sMyData.spException = &e;
273  vAstTranslate(vpAst, (void*)&sMyData);
274 
275  // display the matched AST rule counts
276  printf("\nMatched Rule Counts from AST\n");
277  printf("A: %"PRIuMAX"\n", (luint)sMyData.uiCountA);
278  printf("B: %"PRIuMAX"\n", (luint)sMyData.uiCountB);
279  printf("C: %"PRIuMAX"\n", (luint)sMyData.uiCountC);
280 
281  // display the AST in XML format
282  printf("\nThe AST in XML Format\n");
283  bUtilAstToXml(vpAst, "u", NULL);
284 
285  // free the memory allocation
286  vMemFree(vpMem, spPhrase);
287 
288  }else{
289  // catch block - display the exception location and message
291  iReturn = EXIT_FAILURE;
292  }
293 
294  // free up all allocated resources
295  // NOTE: the trace objects are destroyed by the parser destructor
296  // no need to destroy them separately
297  vParserDtor(vpParser);
298  vApiDtor(vpApi);
299  vMemDtor(vpMem);
300  return iReturn;
301 }
302 
303 
314 int main(int argc, char **argv) {
315  long int iCase = 0;
316  if(argc > 1){
317  iCase = atol(argv[1]);
318  }
319  if((iCase > 0) && (iCase <= s_iCaseCount)){
320  printf("%s\n", s_cppCases[iCase -1]);
321  }
322  switch(iCase){
323  case 1:
324  return iApp();
325  case 2:
326  return iAst();
327  default:
328  return iHelp();
329  }
330 }
331 
XCTOR
#define XCTOR(e)
This macro will initialize an exception structure and prepare entry to the "try" block.
Definition: exception.h:77
vMemDtor
void vMemDtor(void *vpCtx)
Destroys a Memory component. Frees all memory allocated.
Definition: memory.c:141
exception::try
abool try
True for the try block, false for the catch block.
Definition: exception.h:49
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
parser_config::acpInput
const achar * acpInput
Pointer to the input string.
Definition: parser.h:199
ID_AST_POST
#define ID_AST_POST
indicates post-node-traversal AST callback state (up the tree)
Definition: parser.h:92
vpApiCtor
void * vpApiCtor(exception *spEx)
Construct an API component context (object).
Definition: api.c:55
callback_data::uiParserState
aint uiParserState
[read only] ID_ACTIVE if the parser is going down the tree. ID_MATCH or ID_NOMATCH if coming up the t...
Definition: parser.h:158
my_data::uiCountA
aint uiCountA
Definition: main.c:152
uiParserRuleLookup
aint uiParserRuleLookup(void *vpCtx, const char *cpRuleName)
Find the rule index corresponding to a rule name.
Definition: parser.c:440
ID_AST_OK
#define ID_AST_OK
normal AST callback function return
Definition: parser.h:93
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
ast_data
Input data to the AST callback functions.
Definition: ast.h:69
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
vApiDtor
void vApiDtor(void *vpCtx)
The API component destructor.
Definition: api.c:84
vParserSetRuleCallback
void vParserSetRuleCallback(void *vpCtx, aint uiRuleId, parser_callback pfnCallback)
Set a call back function for a specific rule.
Definition: parser.c:386
bUtilAstToXml
abool bUtilAstToXml(void *vpAst, char *cpType, const char *cpFileName)
Convert the AST records to XML format.
Definition: utilities.c:1126
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
parser_config
Defines the input string and other configuration parameters for the parser,.
Definition: parser.h:198
main
int main(int argc, char **argv)
The executable from this main function is the ABNF Parser Generator application, APG.
Definition: main.c:61
ast_data::uiState
aint uiState
Definition: ast.h:74
parser_state
The parser's final state.
Definition: parser.h:183
exception
A structure to describe the type and location of a caught exception.
Definition: exception.h:47
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
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
callback_data
The data struct passed to each callback function.
Definition: parser.h:134
vpMemCtor
void * vpMemCtor(exception *spException)
Construct a memory component.
Definition: memory.c:121
callback_data::vpUserData
void * vpUserData
[input/output] User-defined data passed to to the parser in parser_config.
Definition: parser.h:136
vpAstCtor
void * vpAstCtor(void *vpParserCtx)
The AST object constructor.
Definition: ast.c:51
apg_phrase::uiLength
aint uiLength
The number of characters in the array.
Definition: lib.h:62
vParserDtor
void vParserDtor(void *vpCtx)
Clears the parser component's context and frees all heap memory associated with this parser.
Definition: parser.c:245
ast_data::vpUserData
void * vpUserData
Definition: ast.h:80
my_data
Definition: main.c:150
vUtilApgInfo
void vUtilApgInfo(void)
Display the current state of apg.h.
Definition: utilities.c:60
parser_config::uiStartRule
aint uiStartRule
Index of the start rule. Any rule in the SABNF grammar may be used as the start rule.
Definition: parser.h:201
my_data::uiCountB
aint uiCountB
Definition: main.c:153
my_data::uiCountC
aint uiCountC
Definition: main.c:154
my_data::spException
exception * spException
Definition: main.c:151
spUtilStrToPhrase
apg_phrase * spUtilStrToPhrase(void *vpMem, const char *cpStr)
Convert a null-terminated ASCII string to an apg_phrase.
Definition: utilities.c:891
vApiString
void vApiString(void *vpCtx, const char *cpString, abool bStrict, abool bPppt)
Quicky way to generate a parser from a grammar string.
Definition: api.c:544
vUtilPrintException
void vUtilPrintException(exception *spEx)
Prints exception information from an exception structure.
Definition: utilities.c:415
vUtilCurrentWorkingDirectory
void vUtilCurrentWorkingDirectory(void)
Display the current working directory.
Definition: utilities.c:191
vUtilPrintParserState
void vUtilPrintParserState(parser_state *spState)
Display the parser state in human-readable format to stdout.
Definition: utilities.c:727
apg_phrase::acpPhrase
const achar * acpPhrase
Pointer to an array of type achar APG alphabet characters.
Definition: lib.h:61
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.