# Flex / Bison comparison benchmark # # Runnable harness that builds the same arithmetic grammar with three # tools and compares parse speed, RSS, and CPU on a fixed input # corpus: # # 1. Lime -- bench_arith_grammar.y (already generated by lime) # 2. Bison -- bench_arith.y (Bison-style version of the same grammar) # 3. Flex -- bench_arith.l (lexer paired with the Bison parser) # # When `flex` or `bison` is not on $PATH, the build prints a friendly # diagnostic and skips the comparison cleanly. When both are present # the bench_compare driver runs each parser on the same input, # collects timing + getrusage data, and prints a CSV summary. # Detect tool availability at configure time, including a runtime probe # because some sandboxed environments accept `find_program` for a path # but block invocation. flex_prog / bison_prog are now defined in the # parent bench/meson.build; re-probe their actual invocability here. flex_bison_ok = false if flex_prog.found() and bison_prog.found() fres = run_command(flex_prog, '--version', check : false) bres = run_command(bison_prog, '--version', check : false) if fres.returncode() == 0 and bres.returncode() == 0 # macOS /usr/bin/bison ships GNU Bison 2.3 (GPLv2-licenced; Apple # never updated past it). Our .y files use '%define api.prefix # {bison_}' which requires Bison >= 3.0. Probe the version and # disable the bench cleanly on older bisons rather than failing # the build with a syntax error mid-bison. bison_ver_match = bres.stdout().split('\n')[0] if bison_ver_match.contains('3.') or bison_ver_match.contains('4.') flex_bison_ok = true else message('Flex / Bison bench: DISABLED (bison too old: ' + bison_ver_match + ')') endif endif endif if flex_bison_ok message('Flex / Bison comparison benchmark: ENABLED') # Bison parser bison_gen = custom_target('bench_arith_bison', input : ['bench_arith.y'], output : ['bench_arith.tab.c', 'bench_arith.tab.h'], command : [ bison_prog, '-d', '-o', '@OUTPUT0@', '@INPUT@', ], ) # Flex lexer flex_gen = custom_target('bench_arith_flex', input : ['bench_arith.l'], output : ['bench_arith.lex.c'], command : [ flex_prog, '-o', '@OUTPUT@', '@INPUT@', ], ) # Bison parser for JSON bison_json_gen = custom_target('bench_json_bison', input : ['bench_json.y'], output : ['bench_json.tab.c', 'bench_json.tab.h'], command : [ bison_prog, '-d', '-o', '@OUTPUT0@', '@INPUT@', ], ) # Flex lexer for JSON flex_json_gen = custom_target('bench_json_flex', input : ['bench_json.l'], output : ['bench_json.lex.c'], command : [ flex_prog, '-o', '@OUTPUT@', '@INPUT@', ], ) # Lime parser tables for the same grammar (generated by the # existing bench_arith_gen custom_target above; we just reuse its # outputs). bench_compare = executable('bench_flex_bison_compare', 'bench_flex_bison_compare.c', bison_gen, flex_gen, bison_json_gen, flex_json_gen, bench_arith_gen, bench_json_gen, # Both *_snapshot.c files emit lime_snapshot_entry by default; # suppress one of them via the documented macro guard so the # static link succeeds. ArithBuildSnapshot / JsonParserBuildSnapshot # remain available unconditionally. c_args : ['-DLIME_NO_SNAPSHOT_ENTRY_ALIAS=1'], dependencies : lime_parser_dep, include_directories : include_directories('../../src'), link_args : ['-lm'], ) else message('Flex / Bison comparison benchmark: SKIPPED ' + '(install flex and bison to enable)') endif