-
Notifications
You must be signed in to change notification settings - Fork 0
daxim/grammar-shootout
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Synopsis ======== Fulfill the Perl dependencies. Run: rm -f reports/*.tap perl Marpa-R2.pl knuth-op > reports/knuth-op__Marpa-R2.tap 2>&1 perl Pegex.pl knuth-op > reports/knuth-op__Pegex.tap 2>&1 ./make-report $BROWSER comparison.html Fulfill all dependencies. Run: rm -f reports/*.tap for HARNESS_NAME in *.pl ; do ls -1 grammars/* | parallel \ "perl $HARNESS_NAME {/} > reports/{/}__${HARNESS_NAME}.tap 2>&1" ; done ./make-report $BROWSER comparison.html Description =========== This project tests parsers with numerous grammars and inputs and generates a report table from the results. As of 2019-04, there are 9 parsers under test. There are 62 grammars with corresponding input and output files. Each input/output file has up to 30 lines. There are harnesses in the root directory, driving each parser. A harness takes a grammar file as input and generates source code for a parser in the `generated` directory. Example: $PAGER grammars/knuth-op perl Marpa-R2.pl grammars/knuth-op $PAGER generated/knuth-op__Marpa-R2.pl The harness reads the input file, feeds each input to the parser and compares the parse result to the line in the output file. Example: paste input/knuth-op output/knuth-op If an input has a set of possible parses, the output will be joined with a `␞` character. The comparison is emitted to stdout/stderr in TAP format. Finally, a report generator reads the TAP and creates HTML. In the `reports` directory it expects file names in the format `${GRAMMAR_NAME}__${HARNESS_NAME}.tap`. Examples are given above in the synopsis. Motivation ========== Grammar parsers have a documentation problem. Very often, they do not tell the programmer who wants to use such a library which type of parser or algorithm the library uses under the hood, or at the very least mention the limitations.¹ If the programmer wants to determine whether the library is suitable for his purposes, instead of deciding up-front he has no choice but to try out the software. Multiply this by every programmer who tries out the software. This is a colossal waste of time. There is another problem. Sometimes, the programmer not only parses input under his control, but passes the parser off to an end user. The end user supplies input unforeseen by the programmer, and the parser breaks. Sometimes, it turns out the grammar was not quite correct, and the programmer can amend the grammar. However sometimes, the grammar already was correct, and the flaw is inherent to the parser's algorithm, but the flaw exhibits only under certain input, and so there is nothing the programmer can do to fix it except switch over to a different parser that does not have the algorithmic flaw. Again this is a waste of time. A programmer should be able to make an informed decision which grammar parser is good to use, but the information is incomplete. The goal of this project is to make up for the short-comings in the grammar parser documentations in order to save the interested programmer some time. This is achieved not by amending the various documentations, but by torturing parsers with all kinds of grammars and a multitude of valid inputs and comparing the results. A programmer can then easily pick a grammar parser that passes the tests flawlessly. He can be much more confident that the parser will not break later.² For already existing software that contains a parser, the test results show scenarios where a grammar parser might break, and the programmer can be proactive about the problem without urgency, instead of being confronted out of the blue by a bug report from an end user. The documentation might mention the limitations in an abstract way that would be difficult to understand for some programmers, the comparison shows problems in the concrete which aids to understand them more easily. And lastly, this comparison also functions as a survey of the various APIs of the grammar parsers. By inspecting the generated code, a programmer can get a feel for how much effort it is to put a grammar to use with a certain grammar parser. My personal opinion is that software should reflect the motto: easy things easy, hard things possible. It should be straight-forward to get going with simple parsing tasks, yet the software should be powerful enough to solve the most difficult parsing tasks. Grammar parsers that have unwieldy APIs for no good reason or needlessly expose complexity to the programmer score badly in my mind. ¹ There is at least one grammar parser documentation that outright lies to the programmer. ² In fact, there are grammar parsers whose algorithm is proven to accept any CFG, that is to say the grammar parser is free of algorithmic limitations. It is very desirable to know which grammar parsers are in this category; if you have the choice to pick a grammar parser for a new project, why would you ever pick a flawed one? Requirements ============ Disk space ---------- About 200 MiB for locally installed dependencies and the various generated files. Dependencies ------------ Java wget -P deps -c http://www.antlr.org/download/antlr-4.7.2-complete.jar export CLASSPATH=`realpath deps/antlr-4.7.2-complete.jar`:$CLASSPATH Node npm install --prefix deps antlr4 get-stdin pegjs export NODE_PATH=`realpath deps/node_modules`:$NODE_PATH export PATH=`realpath deps/node_modules/.bin`:$PATH Perl Get `cpanm` from <https://cpanmin.us> or install `cpanminus` or `perl-App-cpanminus` from package manager. cpanm -n -L deps/5 \ Capture::Tiny File::Slurper JSON::MaybeXS Kavorka List::AllUtils \ Marpa::R2 Moops Parse::Eyapp Parse::RecDescent Pegex Regexp::Grammars \ TAP::Parser Text::Xslate Tie::Hash::Indexed export PERL5LIB=`realpath deps/5/lib/perl5`:$PERL5LIB export PATH=`realpath deps/5/bin`:$PATH Perl 6 mkdir -p deps/6 zef install -to=deps/6 JSON::Fast cp ../Zuversicht.pm6 deps # from github.com/daxim export PERL6LIB=`realpath deps`,inst#`realpath deps/6` Shell GNU parallel Troubleshooting =============== Which harness does not work? ---------------------------- For Perl parsers, it is usually enough to compile: › perl -c ${HARNESS_NAME}.pl ${HARNESS_NAME}.pl syntax OK If the parser is in a different programming language, you need a proper trial: › perl ${HARNESS_NAME}.pl trivial ok 1 - trivial__${HARNESS_NAME}.pl a 1..1 It is okay if you cannot satisfy all the dependencies. Simply exclude non-working harnesses from outputting to the `reports` directory because the test output is pointless. Why does a certain combination of parser/grammar/input not work? ---------------------------------------------------------------- First clean up: `rm -rf generated/` Run the harness with the grammar, e.g. `perl Pegex.pl knuth-op` and make note of the particular input line that fails: not ok 3 - knuth-op__Pegex.pl a - a # Failed test 'knuth-op__Pegex.pl a - a' # at Pegex.pl line 152. # got: '' # expected: '["S",["E",["E",["T",["P","a"]]],"-",["T",["P","a"]]]]' You can now run the generated parser directly with a single input and use the usual debugging tools: echo -n 'a - a' | perl generated/knuth-op__Pegex.pl Hacking ======= During development of harnesses, set `PERL5OPT='-M5.024 -Mstrictures'` in the environment. Bugs ==== * Parser versions are not recorded. * Harnesses contain a lot of duplicated code, and it's modestly difficult to find the common code for extraction. * There are too many Perl dependencies. Moops/Kavorka are not heavily used. Perhaps switch over to alternatives that install faster. * There are no tests for the harnesses and report generator. * I had started with a templating engine for code generation in the harnesses, but found it too difficult to debug and switched over to plain appending to a variable. Maybe revisit if a templating engine with excellent debugging capabilities can be found? * Dependencies should be split into the usual run-time, install time, development phases. * Give each report a date identifier and archive the reports so that we can see the improvement of parsers over time. * Determine the overhead of parsers in start-up time. * Test performance with large inputs and determine practical time complexity. * I should have a Makefile for the steps in the synopsis.
About
No description, website, or topics provided.
Resources
Stars
Watchers
Forks
Releases
No releases published
Packages 0
No packages published