APG
… an ABNF Parser Generator
|
APG version 7.0 is written entirely in C. C, of course, is not an object-oriented language. However, using data encapsulation is relatively easy and a crude exception handler can be fashioned from the setjmp()/longjmp()
facility.
APG's exception handling is described in detail elsewhere (exception.h and exception.c). But briefly, any application using an APG parser, or any other of the version 7.0 components, needs to be aware that all fatal error conditions are handled with exceptions and to know how to deal with them. Here is a simple "Hello World" example demonstrating the basic application set up.
Assuming this code is in the file ex.c
which resides in the APG repository directory, to compile and run with the gcc
compiler,
gcc library/exception.c ex.c -o /tmp/ex /tmp/ex
The output should look like
Hello, World oops ex.c:main(10):Hello, Exception!!!
The macro XCTOR(e)
calls setjmp()
, saving the call-stack state of the main()
function and dropping into the user's try block. Fatal errors in APG use the macro XTHROW() to report the error location along with a descriptive message. XTHROW
calls longjmp()
which will restore the call stack state back the the main()
function's XCTOR() call and drop into the caller's catch block.
Data encapsulation is quite easily accomplished in C and APG makes heavy use of it. Most of APG's features, applications, tools and utilities are implemented as data-encapsulated objects, each with its own constructor and destructor. As in the exception handling example above, the object constructor returns a context pointer. That is, a pointer to an opaque chunk of data that holds the state of the object. The destructor will then close any files and free all memory associated with the object, including the context itself.
A constructor function name always ends with Ctor()
.
The function almost always takes a pointer to a valid, initialized exception structure as a first argument.
A destructor function name always ends with Dtor()
.
It always takes its context pointer as a single argument.
In lieu of namespaces, all members of an object's "class" use the object name as a function name prefix. For example, the parser "class" has member functions (ignoring arguments):
void* vpParserCtor(); void vParserDtor(); abool bParserValidate(); void vParserParse(); void vParserSetRuleCallback(); void vParserSetUdtCallback();