diff --git a/spec/propane_spec.rb b/spec/propane_spec.rb index 16fff6c..7d0d612 100644 --- a/spec/propane_spec.rb +++ b/spec/propane_spec.rb @@ -29,7 +29,7 @@ describe Propane do end case options[:language] when "c" - result = system(*%w[gcc -Wall -o spec/run/testparser -Ispec -Ispec/run], *parsers, *test_files) + result = system(*%w[gcc -Wall -o spec/run/testparser -Ispec -Ispec/run], *parsers, *test_files, "spec/testutils.c", "-lm") when "d" result = system(*%w[ldc2 --unittest -of spec/run/testparser -Ispec], *parsers, *test_files, "spec/testutils.d") end @@ -156,7 +156,61 @@ EOF end it "generates a parser that does basic math - user guide example" do - write_grammar < +>> + +ptype size_t; + +token plus /\\+/; +token times /\\*/; +token power /\\*\\*/; +token integer /\\d+/ << + size_t v = 0u; + for (size_t i = 0u; i < match_length; i++) + { + v *= 10; + v += (match[i] - '0'); + } + $$ = v; +>> +token lparen /\\(/; +token rparen /\\)/; +drop /\\s+/; + +Start -> E1 << + $$ = $1; +>> +E1 -> E2 << + $$ = $1; +>> +E1 -> E1 plus E2 << + $$ = $1 + $3; +>> +E2 -> E3 << + $$ = $1; +>> +E2 -> E2 times E3 << + $$ = $1 * $3; +>> +E3 -> E4 << + $$ = $1; +>> +E3 -> E3 power E4 << + $$ = (size_t)pow($1, $3); +>> +E4 -> integer << + $$ = $1; +>> +E4 -> lparen E1 rparen << + $$ = $2; +>> +EOF + when "d" + write_grammar <> @@ -207,6 +261,7 @@ E4 -> lparen E1 rparen << $$ = $2; >> EOF + end build_parser(language: language) compile("spec/test_basic_math_grammar.#{language}", language: language) results = run diff --git a/spec/test_basic_math_grammar.c b/spec/test_basic_math_grammar.c new file mode 100644 index 0000000..4fa1ce2 --- /dev/null +++ b/spec/test_basic_math_grammar.c @@ -0,0 +1,29 @@ +#include "testparser.h" +#include "testutils.h" +#include + +int main() +{ + char const * input = "1 + 2 * 3 + 4"; + p_context_t context; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert_eq(P_SUCCESS, p_parse(&context)); + assert_eq(11, p_result(&context)); + + input = "1 * 2 ** 4 * 3"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert_eq(P_SUCCESS, p_parse(&context)); + assert_eq(48, p_result(&context)); + + input = "(1 + 2) * 3 + 4"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert_eq(P_SUCCESS, p_parse(&context)); + assert_eq(13, p_result(&context)); + + input = "(2 * 2) ** 3 + 4 + 5"; + p_context_init(&context, (uint8_t const *)input, strlen(input)); + assert_eq(P_SUCCESS, p_parse(&context)); + assert_eq(73, p_result(&context)); + + return 0; +} diff --git a/spec/testutils.c b/spec/testutils.c new file mode 100644 index 0000000..7180c66 --- /dev/null +++ b/spec/testutils.c @@ -0,0 +1,12 @@ +#include +#include +#include + +void assert_eq_size_t_i(size_t expected, size_t actual, char const * file, size_t line) +{ + if (expected != actual) + { + fprintf(stderr, "%s:%lu: expected %lu, got %lu\n", file, line, expected, actual); + assert(false); + } +} diff --git a/spec/testutils.h b/spec/testutils.h new file mode 100644 index 0000000..de6ac90 --- /dev/null +++ b/spec/testutils.h @@ -0,0 +1,7 @@ +#pragma once + +void assert_eq_size_t_i(size_t expected, size_t actual, char const * file, size_t line); + +#define assert_eq(expected, actual) \ + assert_eq_size_t_i(expected, actual, __FILE__, __LINE__) +