Skip to content

Top-down and bottom-up parsers for JSON files with C++ API

Notifications You must be signed in to change notification settings

fsossai/json-parser

Repository files navigation

JSON Parser

This is a library written from scratch that provides a top-down (recursive descent) parser for JSON files.

It comprises the C++ API and the following four tools:

  • jcheck checks compliance building the AST.
  • jmatch checks compliance without building the AST.
  • jcolor formats with colors just like jq.
  • jpretty formats with 4-space indentation.
  • jugly formats with no white spaces.
  • gnu/jcheck acts like jcheck but it's made with Bison and Flex.

When using the API, an AST Abstract Syntax Tree is built as a result of the parsing phase. The user can navigate the AST directly jumping from one node to its children or automatically through the visitor pattern.

Every node of the AST build out of the parsing phase matches a production of the CFG grammar defined in grammar.ebnf and formatted in the Extended Backus–Naur form.

GNU Checker with Bison+Flex

For the sake of performance comparison, the gnu directory contains a parser implemented with Bison and Flex. This is a very fast bottom-up parser that we can refer to as a performance baseline.

Bison and Flex can be installed with apt install bison and apt install flex respectively.

Install

make install
source enable

will install the header files and the shared library. The installation directory is install by default, to change it use make PREFIX=/path.

The Bison+Flex implementation is not included but can be compiled with make gnu/check.

Build Upon It

After making sure that the library has been sourced (source enable) you can easily link it to your own tool:

g++ YourTool.cpp $(pkg-config --cflags --libs jpaser)

API Examples

For a complete use case check out tools/Pretty.cpp.

You can implement customized visitors by extending the class Visitor.

json_parser::Object object;
if (object.From("{\"mixed\": [1,2.3,"four"]")) {
  PrettyVisitor pv;
  object.Accept(pv);
  cout << pv.GetResult();
}

will print

{
    "mixed": [
        1,
        2.3,
        "four"
    ]
}

Try implementing a your variant that does something more special!

Benchmarking

To run a parsing benchmark on the set of JSON files provided in data/benchmark use make benchmark. The command uses jmatch as the default program during the benchmark, to set another one set the CMD make variable.

source enable
cd benchmark
make

The command will produce an output like the following:

file                              size[MB]  time[s]  speed[MB/s]
data/benchmark/canada.json        2.146     .084     25.547
data/benchmark/citm_catalog.json  1.647     .046     35.804
data/benchmark/twitter.json       .602      .021     28.666

Try comparing it against the popular JSON processor!

make benchmark CMD=jq

Testing

To run a compliance test:

make test
  • Files in tests/fail are supposed to be rejected.
  • Files in tests/pass are supposed to be accepted.

These files have been taken from json.org.

See also Native JSON Benchmark for more information.

$cat author.json

{
    "name": "Federico Sossai",
    "country": "Italy",
    "year": 2022,
    "email": "federico.sossai@gmail.com"
}