Awesome
What is dpaparser?
dpaparser is a parser generater, currently only for parsing yaml files. Templates, which are valid c source and header files, define a macro specifying all structures & fields to be parsed, and include the parser generator, which generates a valid c header if it is included as normal in a c source or header, and generates a valid c source if compiled using the dpaparser script.
The parser is generated by the dpaparser script which is implemented as an executable make script. More specifically, it's a script which uses make as it's interpreter, and is a normal make file otherwise. It uses a c compiler to compile the parser code.
WTF, why?
I quickly needed a high level c yaml parser and didn't want to have to deal with writing and messing with yaml parser code to fill structures using a lower level yaml parser all the time. This was originally included in another project, but I wanted to use it in other projects too, which is why this exists and why this is solved in such an unusual way.
How do I use it?
Building & installing
Bulding the libdpaparser.a library:
make
Installing the library, include files, and dpaparser script:
sudo make PREFIX=/usr/local install
PREFIX specifies the install location. /usr/local is the default.
Uninstalling it:
sudo make PREFIX=/usr/local uninstall
Using dpaparser
Make sure all your templates are in some folder and have the .template extension. You can include these templates into your c program and they'll be valid c headers. To generate the parser code, use the following command:
dpaparser TEMPLATE=my_template_dir/ TEMPLATE_A=lib/libmytemplateparsers.a
This will generate & compile the parser code for all templates in the template directory
specified by TEMPLATE
, and generate a static library at wherever TEMPLATE_A
specifies
containing them. It will temporarely store the objectfiles at BUILD=build
and uses the
compiler specified using CC
. To use these libraries, you need to link against it,
the dpaparser static library, and if you use the yaml parser generater, against the
yaml library too.
Use the following macros for parsing:
PARSE_YAML( TYPE, FILE, POINTER_TO_STRUCTURE_POINTER );
FREE_YAML( TYPE, POINTER_TO_STRUCTURE_POINTER );
An example how to use these macros, assuming the template further below:
FILE *file = fopen("example.yaml", "r");
if(!file){
fprintf(stderr,"Failed to open file!\n");
exit(1);
}
gen_my_structure_t* result;
if( !PARSE_YAML(unitscript,file,&result) || !result ){
fprintf(stderr,"something went wrong!\n");
fclose(file);
exit(1);
}
fclose(file);
if(result->some_integer_property){
printf("'a' was set to %ld\n", *result->some_integer_property);
}else{
printf("'a' not found");
}
FREE_YAML( my_structure, &result );
Templete example & details
// Include guard
#ifndef THE_INCLUDE_GUARD
#define THE_INCLUDE_GUARD
// Include any code you want and is suitable to a c header
...
// The templates
#define PARSABLE_STRUCTURES \
BLOCK( my_structure, ( \
ENTRY( string, "the yaml property", the_string_property ) \
ENTRY( integer, "a", some_integer_property ) \
ENTRY( boolean, "b", some_boolean_property ) \
ENTRY( map, "c", some_map ) \
ENTRY( list, "d", some_list ) \
PRIVATE( \
size_t some_other_properties_not_parsed; \
size_t some_other_properties_not_parsed2; \
) \
))
// This header generates the c structures, declarations, functions, yaml parsercode, etc.
#include <dpaparser/yaml>
#endif
The ENTRY
and PRIVATE
macros are optional. The types specified in ENTRY
and BLOCK
correspond to the gen_ ## typename ## _t
and struct gen_ ## typename
type.
The type of an ENTRY
can be one defined by a BLOCK
.
Each entry is a struct field, and it's always a pointer which is null if tha yaml file didn't include it.
Using other types than strings as values of maps and lists is currently not supported.