From f40ae41331390dfe3f327fee908062b1d0fb0772 Mon Sep 17 00:00:00 2001 From: Cyril Adrian Date: Thu, 12 Apr 2012 22:41:40 +0200 Subject: [PATCH] fixed tag management --- .../parse/grammar/packrat/packrat_grammar.e | 49 +++++++---- test/lib/parse/test_packrat03.e | 4 +- test/lib/parse/test_packrat04.e | 83 +++++++++++++++++++ 3 files changed, 118 insertions(+), 18 deletions(-) create mode 100644 test/lib/parse/test_packrat04.e diff --git a/src/lib/parse/grammar/packrat/packrat_grammar.e b/src/lib/parse/grammar/packrat/packrat_grammar.e index 57e8e684e9..95ce501414 100644 --- a/src/lib/parse/grammar/packrat/packrat_grammar.e +++ b/src/lib/parse/grammar/packrat/packrat_grammar.e @@ -48,7 +48,7 @@ feature {} reducer = a_reducer end - the_table: PARSE_TABLE[PACKRAT_PARSE_CONTEXT] is + default_table: PARSE_TABLE[PACKRAT_PARSE_CONTEXT] is once Result := {PARSE_TABLE[PACKRAT_PARSE_CONTEXT] << -- ---------------------------------------------------------------------- @@ -158,11 +158,10 @@ feature {} feature {ANY} table: PARSE_TABLE[PACKRAT_PARSE_CONTEXT] is do - Result := table_memory - if Result = Void then - Result := the_table - table_memory := Result + if table_memory = Void then + reset_table end + Result := table_memory end reset is @@ -171,6 +170,22 @@ feature {ANY} reset_build_data end +feature {EIFFELTEST_TOOLS} -- test only + set_table (a_table: like table; a_root: like root) is + do + table_memory := a_table + root := a_root + ensure + table = a_table + end + + root: STRING + + reset_table is + do + set_table(default_table, once "grammar") + end + feature {} -- low-level parsers parse_string (buffer: MINI_PARSER_BUFFER; string: STRING): PACKRAT_IMAGE is local @@ -269,6 +284,7 @@ feature {} -- low-level parsers string: STRING do if not buffer.end_reached then + string := once "" string.clear_count string.extend(buffer.current_character) if regex.match(string) then @@ -354,7 +370,7 @@ feature {} -- buffer moves end feature {ANY} - parse_table (a_source: ABSTRACT_STRING): like the_table is + parse_table (a_source: ABSTRACT_STRING): like default_table is require a_source /= Void local @@ -363,10 +379,14 @@ feature {ANY} i: INTEGER key: FIXED_STRING; item: PARSE_ATOM[PACKRAT_PARSE_CONTEXT] do + if table_memory = Void then + reset_table + end + create parser create buffer.initialize_with(a_source) - if parser.eval(buffer, table, once "grammar") then + if parser.eval(buffer, table, root) and then parser.error = Void then create Result.with_capacity(last_atoms.count) from i := last_atoms.lower @@ -378,9 +398,13 @@ feature {ANY} Result.add(key, item) i := i + 1 end + else + error := parser.error end end + error: PARSE_ERROR + feature {} -- build the grammar reducer: PACKRAT_REDUCER @@ -533,19 +557,12 @@ feature {} -- build the grammar end reduce_alternative_tag is - local - sequence: PACKRAT_SEQUENCE do check last_lookahead = lookahead_none end if not last_tag.is_empty then - if sequence ?:= last_primary then - sequence ::= last_primary - sequence.set_tag(last_tag) - else - last_primary := seq(<< last_primary >>, one, last_tag, agent reducer.reduce_with_tag(last_nonterminal_def.intern, last_tag.intern)) - end + last_primary := seq(<< last_primary >>, one, last_tag, agent reducer.reduce_with_tag(last_nonterminal_def.intern, last_tag.intern)) reset_tag end last_alternative.add_last(last_primary) @@ -617,7 +634,7 @@ feature {} -- build the grammar terminal_name := ("[#(1)]" # last_charclass).intern terminal ::= atom(terminal_name) if terminal = Void then - regex := regex_factory.convert_posix_pattern(last_charclass) + regex := regex_factory.convert_posix_pattern(terminal_name.out) create terminal.make(agent parse_regex(?, regex), agent reduce_image_regex) add_atom(terminal_name, terminal) end diff --git a/test/lib/parse/test_packrat03.e b/test/lib/parse/test_packrat03.e index 3087b93425..380d96528c 100644 --- a/test/lib/parse/test_packrat03.e +++ b/test/lib/parse/test_packrat03.e @@ -23,10 +23,10 @@ feature {} source := "[ grammar <- (nonterminal '<-' sp pattern {rule})+ {grammar} -pattern <- alternative ('/' sp alternative)* +pattern <- alternative {first_alternative} ('/' sp alternative {next_alternative})* {alternative} alternative <- ([!&] sp suffix / suffix tag?)+ suffix <- primary ([*+?] sp)* -primary <- '(' sp pattern ')' sp / '.' sp / literal / charclass / nonterminal !'<-' +primary <- '(' sp pattern {nested} ')' sp / '.' sp / literal / charclass / nonterminal !'<-' literal <- ['] (!['] .)* ['] sp charclass <- '[' (!']' (. '-' . / .))* ']' sp nonterminal <- [a-zA-Z]+ sp diff --git a/test/lib/parse/test_packrat04.e b/test/lib/parse/test_packrat04.e new file mode 100644 index 0000000000..ba69edae2d --- /dev/null +++ b/test/lib/parse/test_packrat04.e @@ -0,0 +1,83 @@ +class TEST_PACKRAT04 + +inherit + PACKRAT_REDUCER + +insert + EIFFELTEST_TOOLS + LOGGING + +create {} + make + +feature {} + make is + local + grammar: PACKRAT_GRAMMAR + table: PARSE_TABLE[PACKRAT_PARSE_CONTEXT] + source: STRING; dump: STRING_OUTPUT_STREAM + parser: PACKRAT_PARSER; buffer: MINI_PARSER_BUFFER + do + create grammar.make(Current) + + -- this one is the extended grammar (with tags), + -- decorated with tags + + source := "[ +grammar <- sp (nonterminal '<-' sp pattern {rule})+ {grammar} +pattern <- alternative {first_alternative} ('/' sp alternative {next_alternative})* {alternative} +alternative <- ([!&] sp suffix / suffix tag?)+ +suffix <- primary ([*+?] sp)* +primary <- '(' sp pattern {nested} ')' sp / '.' sp / literal / charclass / nonterminal !'<-' +literal <- ['] (!['] .)* ['] sp +charclass <- '[' (!']' (. '-' . / .))* ']' sp +nonterminal <- [a-zA-Z]+ sp +sp <- [ \t\n]* +tag <- '{' (!'}' .)+ '}' sp + +]" + + table := grammar.parse_table(source) + assert(table /= Void) + table.pretty_print_on(log.info) + create dump.make + table.pretty_print_on(dump) + assert(source.is_equal(dump.to_string)) + + create parser + create buffer.initialize_with(source) + assert(parser.eval(buffer, table, "grammar") and then parser.error = Void) + end + +feature {PACKRAT_GRAMMAR} + reduce_alternative (nonterminal_name: FIXED_STRING) is + do + log.trace.put_line("#### reduce alternative: nonterminal %"#(1)%"" # nonterminal_name) + end + + reduce_pattern (nonterminal_name: FIXED_STRING) is + do + log.trace.put_line("#### reduce pattern: nonterminal %"#(1)%"" # nonterminal_name) + end + + reduce_positive_lookahead (nonterminal_name: FIXED_STRING) is + do + log.trace.put_line("#### reduce positive lookahead: nonterminal %"#(1)%"" # nonterminal_name) + end + + reduce_negative_lookahead (nonterminal_name: FIXED_STRING) is + do + log.trace.put_line("#### reduce negative lookahead: nonterminal %"#(1)%"" # nonterminal_name) + end + + reduce_loop (nonterminal_name: FIXED_STRING; quantifier: INTEGER_8) is + do + log.trace.put_line("#### reduce loop: nonterminal %"#(1)%", #(2)" # nonterminal_name # quantifier.out) + end + + reduce_with_tag (nonterminal_name, tag: FIXED_STRING) is + do + log.trace.put_line("#### reduce tag: nonterminal %"#(1)%", tag {#(2)}" # nonterminal_name # tag) + end + +end