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 * *************************************************************************************/
83 #include "../../utilities/utilities.h"
84 #include "../../api/api.h"
85 
86 #include "source.h"
87 
88 static const char* cpMakeFileName(char* cpBuffer, const char* cpBase, const char* cpDivider, const char* cpName){
89  strcpy(cpBuffer, cpBase);
90  strcat(cpBuffer, cpDivider);
91  strcat(cpBuffer, cpName);
92  return cpBuffer;
93 }
94 
95 static char s_caBuf[PATH_MAX];
96 
97 static char* s_cpDescription =
98  "Illustrate construction of and API object and demonstrate its features.";
99 
100 static char* s_cppCases[] = {
101  "Display application information.",
102  "Input, concatenate and display multiple grammar files.",
103  "Input, validation fails with bad characters and no final EOL.",
104  "Illustrate a grammar with bad syntax.",
105  "Illustrate a grammar with bad semantics.",
106  "Illustrate generating a parser with and without PPPT.",
107 };
108 static long int s_iCaseCount = (long int)(sizeof(s_cppCases) / sizeof(s_cppCases[0]));
109 static void vPrintCase(long int iCase){
110  if((iCase > 0) && (iCase <= s_iCaseCount)){
111  printf("%s\n", s_cppCases[iCase -1]);
112  }else{
113  printf("unknown case number %ld\n", iCase);
114  }
115 }
116 
117 static int iHelp(void){
118  long int i = 0;
120  printf("description: %s\n", s_cpDescription);
121  printf(" usage: ex-api arg\n");
122  printf(" arg = n, 1 <= n <= %ld\n", s_iCaseCount);
123  printf(" execute case number n\n");
124  printf(" arg = anthing else\n");
125  printf(" print this help screen\n");
126  printf("\n");
127  for(; i < s_iCaseCount; i++){
128  printf("case %ld %s\n", (i + 1), s_cppCases[i]);
129  }
130  return EXIT_SUCCESS;
131 }
132 
133 static int iApp() {
134  // print the current working directory
136  printf("\n");
137 
138  // display the current APG sizes and macros
139  vUtilApgInfo();
140  return EXIT_SUCCESS;
141 }
142 
143 static int iInCat() {
144  int iReturn = EXIT_SUCCESS;
145  static void* vpApi = NULL;
146  char* cpFloatMid =
147  "integer = 1*%d48-57\n"
148  "dot = \".\"\n";
149  exception e;
150  XCTOR(e);
151  if(e.try){
152  // try block
153 
154  // construct the parser from the pre-generated grammar files
155  vpApi = vpApiCtor(&e);
156 
157  // concatenate the grammar from three sources
158  cpApiInFile(vpApi, cpMakeFileName(s_caBuf, SOURCE_DIR, "/../input/", "float-top.abnf"));
159  cpApiInString(vpApi, cpFloatMid);
160  cpApiInFile(vpApi, cpMakeFileName(s_caBuf, SOURCE_DIR, "/../input/", "float-bot.abnf"));
161 
162  // display the concatenated grammar
163  printf("\nThe Concatenated Grammar\n");
164  vApiInToAscii(vpApi, NULL);
165 
166  }else{
167  // catch block - display the exception location and message
169  iReturn = EXIT_FAILURE;
170  }
171  vApiDtor(vpApi);
172  return iReturn;
173 }
174 
175 static int iInBadChars() {
176  int iReturn = EXIT_SUCCESS;
177  static void* vpApi = NULL;
178  char* cpFloat =
179  "float = sign decimal \x80 exponent\n"
180  "sign = [\"+\" / \"-\"]\n"
181  "decimal = integer [dot fraction]\n"
182  " / dot \xFF fraction\n"
183  "integer = 1*%d48-57\n"
184  "dot = \".\"\n"
185  "fraction = *%d48-57\n"
186  "exponent = [\"e\" esign exp]\n"
187  "esign = [\"+\" / \"-\"]\n"
188  "\n"
189  "exp = 1*%d48-57";
190  exception e;
191  XCTOR(e);
192  if(e.try){
193  // try block
194 
195  // construct the parser from the pre-generated grammar files
196  vpApi = vpApiCtor(&e);
197 
198  // validate the grammar
199  cpApiInString(vpApi, cpFloat);
200  vApiInValidate(vpApi, APG_FALSE);
201 
202  // display the concatenated grammar (will never be executed)
203  vApiInToAscii(vpApi, NULL);
204 
205  }else{
206  // catch block - display the exception location and message
208 
209  // display the error log
210  printf("\nThe Grammar Errors\n");
211  void* vpLog = vpApiGetErrorLog(vpApi);
212  vUtilPrintMsgs(vpLog);
213 
214  printf("\nThe Full Grammar\n");
215  vApiInToAscii(vpApi, NULL);
216  iReturn = EXIT_FAILURE;
217  }
218  vApiDtor(vpApi);
219  return iReturn;
220 }
221 
222 static int iInBadSyntax() {
223  int iReturn = EXIT_SUCCESS;
224  static void* vpApi = NULL;
225  char* cpFloat =
226  "float = sign decimal exponent\n"
227  "sign = [\"+\" / \"-\"]\n"
228  "decimal = integer [dot fraction]\n"
229  " / dot fraction\n"
230  "integer = 1*%d48-57\n"
231  "1dot = \".\"\n"
232  "fraction = *%d48-57\n"
233  "exponent = [\"e\" esign exp]\n"
234  "esign = [\"+\" / \"-\"]\n"
235  "\n"
236  "exp = 1*%d48-57\n";
237  exception e;
238  XCTOR(e);
239  if(e.try){
240  // try block
241 
242  // construct the parser from the pre-generated grammar files
243  vpApi = vpApiCtor(&e);
244 
245  // validate the grammar
246  cpApiInString(vpApi, cpFloat);
247  vApiInValidate(vpApi, APG_FALSE);
248  vApiSyntax(vpApi, APG_FALSE);
249 
250  // display the concatenated grammar (will never be executed)
251  vApiInToAscii(vpApi, NULL);
252 
253  }else{
254  // catch block - display the exception location and message
256 
257  // display the error log
258  printf("\nThe Grammar Errors\n");
259  void* vpLog = vpApiGetErrorLog(vpApi);
260  vUtilPrintMsgs(vpLog);
261 
262  printf("\nThe Full Grammar\n");
263  vApiInToAscii(vpApi, NULL);
264  iReturn = EXIT_FAILURE;
265  }
266  vApiDtor(vpApi);
267  return iReturn;
268 }
269 
270 static int iInBadSemantics() {
271  int iReturn = EXIT_SUCCESS;
272  static void* vpApi = NULL;
273  char* cpFloat =
274  "float = sign decimal exponent\n"
275  "sign = [\"+\" / \"-\"]\n"
276  "decimal = integer [dot fraction]\n"
277  " / dot fraction\n"
278  "integer = 1*%d57-48\n"
279  "dot = \".\"\n"
280  "fraction = *%d48-57\n"
281  "exponent = [\"e\" esign exp]\n"
282  "esign = [\"+\" / \"-\"]\n"
283  "\n"
284  "exp = 1*%d48-57\n";
285  exception e;
286  XCTOR(e);
287  if(e.try){
288  // try block
289 
290  // construct the parser from the pre-generated grammar files
291  vpApi = vpApiCtor(&e);
292 
293  // validate the grammar
294  cpApiInString(vpApi, cpFloat);
295  vApiInValidate(vpApi, APG_FALSE);
296  vApiSyntax(vpApi, APG_FALSE);
297  vApiOpcodes(vpApi);
298 
299  // display the concatenated grammar (will never be executed)
300  vApiInToAscii(vpApi, NULL);
301 
302  }else{
303  // catch block - display the exception location and message
305 
306  // display the error log
307  printf("\nThe Grammar Errors\n");
308  void* vpLog = vpApiGetErrorLog(vpApi);
309  vUtilPrintMsgs(vpLog);
310 
311  printf("\nThe Full Grammar\n");
312  vApiInToAscii(vpApi, NULL);
313  iReturn = EXIT_FAILURE;
314  }
315  vApiDtor(vpApi);
316  return iReturn;
317 }
318 
319 static int iInPppt() {
320  int iReturn = EXIT_SUCCESS;
321  static void* vpMem = NULL;
322  static void* vpApi = NULL;
323  static void* vpParser = NULL;
324  static void* vpPpptParser = NULL;
325  char* cpInput = "{"
326  "\"array\": [1,2,3,4],"
327  "\"object\": {\"t\": true, \"f\": false, \"n\":null}"
328  "}";
329  pppt_size sPpptSize;
330  parser_config sConfig;
331  parser_state sState;
332  apg_phrase* spPhrase;
333  exception e;
334  XCTOR(e);
335  if(e.try){
336  // try block
337 
338  // construct the parser from the pre-generated grammar files
339  vpApi = vpApiCtor(&e);
340 
341  // construct a memory object for string conversion
342  vpMem = vpMemCtor(&e);
343  spPhrase = spUtilStrToPhrase(vpMem, cpInput);
344 
345  // validate the grammar
346  cpApiInFile(vpApi, cpMakeFileName(s_caBuf, SOURCE_DIR, "/../input/", "json.abnf"));
347  vApiInValidate(vpApi, APG_FALSE);
348  vApiSyntax(vpApi, APG_FALSE);
349  vApiOpcodes(vpApi);
350  bApiAttrs(vpApi);
351 
352  // display the PPPT size
353  printf("\nThe PPPT sizes\n");
354  vApiPpptSize(vpApi, &sPpptSize);
355  printf("minimum alphabet character: %"PRIuMAX"\n", sPpptSize.luiAcharMin);
356  printf("maximum alphabet character: %"PRIuMAX"\n", sPpptSize.luiAcharMax);
357  printf(" bytes per PPPT map: %"PRIuMAX"\n", sPpptSize.luiMapSize);
358  printf(" number of maps in table: %"PRIuMAX"\n", sPpptSize.luiMaps);
359  printf(" total table size in bytes: %"PRIuMAX"\n", sPpptSize.luiTableSize);
360 
361  // parse without PPPT
362  vpParser = vpApiOutputParser(vpApi);
363  memset(&sConfig, 0, sizeof(sConfig));
364  sConfig.acpInput = spPhrase->acpPhrase;
365  sConfig.uiInputLength = spPhrase->uiLength;
366  sConfig.uiStartRule = uiParserRuleLookup(vpParser, "JSON-text");
367  vParserParse(vpParser, &sConfig, &sState);
368  printf("\nState showing node hits without PPPT\n");
369  vUtilPrintParserState(&sState);
370 
371  // parse with PPPT
372  vApiPppt(vpApi, NULL, 0);
373  vpPpptParser = vpApiOutputParser(vpApi);
374  memset(&sConfig, 0, sizeof(sConfig));
375  sConfig.acpInput = spPhrase->acpPhrase;
376  sConfig.uiInputLength = spPhrase->uiLength;
377  sConfig.uiStartRule = uiParserRuleLookup(vpParser, "JSON-text");
378  vParserParse(vpPpptParser, &sConfig, &sState);
379  printf("\nState showing node hits with PPPT\n");
380  vUtilPrintParserState(&sState);
381 
382  }else{
383  // catch block - display the exception location and message
385  iReturn = EXIT_FAILURE;
386  }
387  vParserDtor(vpParser);
388  vParserDtor(vpPpptParser);
389  vApiDtor(vpApi);
390  vMemDtor(vpMem);
391  return iReturn;
392 }
393 
401 int main(int argc, char **argv) {
402  long int iCase = 0;
403  if(argc > 1){
404  iCase = atol(argv[1]);
405  }
406  switch(iCase){
407  case 1:
408  vPrintCase(1);
409  return iApp();
410  case 2:
411  vPrintCase(2);
412  return iInCat();
413  case 3:
414  vPrintCase(3);
415  return iInBadChars();
416  case 4:
417  vPrintCase(4);
418  return iInBadSyntax();
419  case 5:
420  vPrintCase(5);
421  return iInBadSemantics();
422  case 6:
423  vPrintCase(6);
424  return iInPppt();
425  default:
426  return iHelp();
427  }
428 }
429 
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
vApiPpptSize
void vApiPpptSize(void *vpCtx, pppt_size *spSize)
Compute the size of the PPPT maps and the number of bytes for the entire table.
Definition: pppt.c:246
parser_config::acpInput
const achar * acpInput
Pointer to the input string.
Definition: parser.h:199
vpApiCtor
void * vpApiCtor(exception *spEx)
Construct an API component context (object).
Definition: api.c:55
vUtilPrintMsgs
void vUtilPrintMsgs(void *vpMsgs)
Display the list of messages in a message object to stdout.
Definition: utilities.c:747
uiParserRuleLookup
aint uiParserRuleLookup(void *vpCtx, const char *cpRuleName)
Find the rule index corresponding to a rule name.
Definition: parser.c:440
vApiInValidate
void vApiInValidate(void *vpCtx, abool bStrict)
Scans the input SABNF grammar for invalid characters and line ends.
Definition: input.c:204
pppt_size::luiMapSize
luint luiMapSize
The size, in bytes, of a single PPPT table entry (map).
Definition: api.h:86
vApiOpcodes
void vApiOpcodes(void *vpCtx)
Parse the SABNF grammar and translate its AST into opcodes for all the rules.
Definition: semantics.c:64
vApiDtor
void vApiDtor(void *vpCtx)
The API component destructor.
Definition: api.c:84
vpApiGetErrorLog
void * vpApiGetErrorLog(void *vpCtx)
Get the internal message log.
Definition: api.c:117
pppt_size::luiAcharMax
luint luiAcharMax
The maximum character size in the grammar alphabet.
Definition: api.h:85
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
pppt_size::luiMaps
luint luiMaps
The number of maps needed.
Definition: api.h:87
main
int main(int argc, char **argv)
The executable from this main function is the ABNF Parser Generator application, APG.
Definition: main.c:61
vApiSyntax
void vApiSyntax(void *vpCtx, abool bStrict)
Parse the SABNF grammar to validate that the grammar structure is valid.
Definition: syntax.c:51
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
pppt_size::luiTableSize
luint luiTableSize
The memory requirement, in bytes, of the full table.
Definition: api.h:88
vpApiOutputParser
void * vpApiOutputParser(void *vpCtx)
Generate a parser object directly from the specified SABNF grammar.
Definition: output.c:217
bApiAttrs
abool bApiAttrs(void *vpCtx)
Computes the grammar's attributes.
Definition: attributes.c:79
pppt_size
Size information for the **P**artially-**P**redictive **P**arsing **T**ables (PPPT) data.
Definition: api.h:83
vpMemCtor
void * vpMemCtor(exception *spException)
Construct a memory component.
Definition: memory.c:121
cpApiInFile
const char * cpApiInFile(void *vpCtx, const char *cpFileName)
Reads an SABNF grammar byte stream from a file.
Definition: input.c:117
pppt_size::luiAcharMin
luint luiAcharMin
The minimum character size in the grammar alphabet.
Definition: api.h:84
vApiInToAscii
void vApiInToAscii(void *vpCtx, const char *cpFileName)
Display the input lines with line numbers and character offsets.
Definition: input.c:261
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
vParserDtor
void vParserDtor(void *vpCtx)
Clears the parser component's context and frees all heap memory associated with this parser.
Definition: parser.c:245
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
spUtilStrToPhrase
apg_phrase * spUtilStrToPhrase(void *vpMem, const char *cpStr)
Convert a null-terminated ASCII string to an apg_phrase.
Definition: utilities.c:891
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
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.