From 31970522deaba95d90246c270e30d3cb164e90fa Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Wed, 12 Oct 2022 20:56:14 -0400 Subject: [PATCH] Store parse result; add result_type grammar keyword --- assets/parser.d.erb | 21 ++++++++++++++++----- lib/propane/grammar.rb | 10 ++++++++++ spec/propane/grammar_spec.rb | 24 +++++++++++++----------- 3 files changed, 39 insertions(+), 16 deletions(-) diff --git a/assets/parser.d.erb b/assets/parser.d.erb index 41ad6ef..221aea4 100644 --- a/assets/parser.d.erb +++ b/assets/parser.d.erb @@ -343,6 +343,17 @@ class <%= @classname %> uint n_reduce_entries; } + private struct StateResult + { + uint state; + <%= @grammar.result_type %> result; + + this(uint state) + { + this.state = state; + } + } + <% state_table, shift_table, reduce_table = @parser.build_tables %> private static immutable Shift shifts[] = [ <% shift_table.each do |shift| %> @@ -373,7 +384,7 @@ class <%= @classname %> { Lexer.LexedToken lexed_token; uint token = _TOKEN_COUNT; - uint[] states = new uint[](1); + StateResult[] states = new StateResult[](1); uint reduced_rule_set = 0xFFFFFFFFu; for (;;) { @@ -385,11 +396,11 @@ class <%= @classname %> uint shift_state = 0xFFFFFFFFu; if (reduced_rule_set != 0xFFFFFFFFu) { - shift_state = check_shift(states[$-1], reduced_rule_set); + shift_state = check_shift(states[$-1].state, reduced_rule_set); } if (shift_state == 0xFFFFFFFFu) { - shift_state = check_shift(states[$-1], token); + shift_state = check_shift(states[$-1].state, token); } if (shift_state != 0xFFFFFFFFu) { @@ -398,7 +409,7 @@ class <%= @classname %> /* Successful parse. */ return true; } - states ~= shift_state; + states ~= StateResult(shift_state); if (reduced_rule_set == 0xFFFFFFFFu) { token = _TOKEN_COUNT; @@ -410,7 +421,7 @@ class <%= @classname %> continue; } - uint reduce_index = check_reduce(states[$-1], token); + uint reduce_index = check_reduce(states[$-1].state, token); if (reduce_index != 0xFFFFFFFFu) { reduced_rule_set = reduces[reduce_index].rule_set; diff --git a/lib/propane/grammar.rb b/lib/propane/grammar.rb index bf45596..f737bf7 100644 --- a/lib/propane/grammar.rb +++ b/lib/propane/grammar.rb @@ -8,6 +8,7 @@ class Propane attr_reader :rules attr_reader :tokens attr_reader :code_blocks + attr_reader :result_type def initialize(input) @patterns = [] @@ -18,6 +19,7 @@ class Propane @next_line_number = @line_number @mode = nil @input = input.gsub("\r\n", "\n") + @result_type = "void *" parse_grammar! end @@ -35,6 +37,7 @@ class Propane elsif @mode.nil? && parse_mode_label! elsif parse_module_statement! elsif parse_class_statement! + elsif parse_result_type_statement! elsif parse_pattern_statement! elsif parse_token_statement! elsif parse_tokenid_statement! @@ -83,6 +86,13 @@ class Propane end end + def parse_result_type_statement! + if consume!(/result_type\s+/) + md = consume!(/([^;]+);/, "expected result type expression") + @result_type = md[1].strip + end + end + def parse_token_statement! if consume!(/token\s+/) md = consume!(/([a-zA-Z_][a-zA-Z_0-9]*)/, "expected token name") diff --git a/spec/propane/grammar_spec.rb b/spec/propane/grammar_spec.rb index ed5845d..2d795b4 100644 --- a/spec/propane/grammar_spec.rb +++ b/spec/propane/grammar_spec.rb @@ -6,6 +6,7 @@ class Propane module a.b; class Foobar; +result_type XYZ * ; token while; @@ -31,47 +32,48 @@ EOF grammar = Grammar.new(input) expect(grammar.classname).to eq "Foobar" expect(grammar.modulename).to eq "a.b" + expect(grammar.result_type).to eq "XYZ *" o = grammar.tokens.find {|token| token.name == "while"} expect(o).to_not be_nil - expect(o.line_number).to eq 6 + expect(o.line_number).to eq 7 o = grammar.patterns.find {|pattern| pattern.token == o} expect(o).to_not be_nil expect(o.pattern).to eq "while" - expect(o.line_number).to eq 6 + expect(o.line_number).to eq 7 expect(o.code).to be_nil o = grammar.tokens.find {|token| token.name == "id"} expect(o).to_not be_nil - expect(o.line_number).to eq 9 + expect(o.line_number).to eq 10 o = grammar.patterns.find {|pattern| pattern.token == o} expect(o).to_not be_nil expect(o.pattern).to eq "[a-zA-Z_][a-zA-Z_0-9]*" - expect(o.line_number).to eq 9 + expect(o.line_number).to eq 10 expect(o.code).to be_nil o = grammar.tokens.find {|token| token.name == "token_with_code"} expect(o).to_not be_nil - expect(o.line_number).to eq 11 + expect(o.line_number).to eq 12 o = grammar.patterns.find {|pattern| pattern.token == o} expect(o).to_not be_nil expect(o.pattern).to eq "token_with_code" - expect(o.line_number).to eq 11 + expect(o.line_number).to eq 12 expect(o.code).to eq "Code for the token\n" o = grammar.tokens.find {|token| token.name == "token_with_no_pattern"} expect(o).to_not be_nil - expect(o.line_number).to eq 15 + expect(o.line_number).to eq 16 o = grammar.patterns.find {|pattern| pattern.token == o} expect(o).to be_nil o = grammar.patterns.find {|pattern| pattern.pattern == "\\s+"} expect(o).to_not be_nil - expect(o.line_number).to eq 17 + expect(o.line_number).to eq 18 expect(o.token).to be_nil expect(o.code).to be_nil @@ -80,19 +82,19 @@ EOF o = grammar.rules[0] expect(o.name).to eq "A" expect(o.components).to eq %w[B] - expect(o.line_number).to eq 19 + expect(o.line_number).to eq 20 expect(o.code).to eq " a = 42;\n" o = grammar.rules[1] expect(o.name).to eq "B" expect(o.components).to eq %w[C while id] - expect(o.line_number).to eq 22 + expect(o.line_number).to eq 23 expect(o.code).to be_nil o = grammar.rules[2] expect(o.name).to eq "B" expect(o.components).to eq [] - expect(o.line_number).to eq 23 + expect(o.line_number).to eq 24 expect(o.code).to eq " b = 0;\n" end