From d6e5c4325d1eb294e8f2df7d2761e987a504fe60 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Tue, 7 Jun 2022 22:25:31 -0400 Subject: [PATCH] Add new start rule ending with EOF token rather than appending EOF token to all user-specified start rules --- lib/propane/grammar.rb | 8 ++++++-- lib/propane/parser.rb | 14 ++++++-------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lib/propane/grammar.rb b/lib/propane/grammar.rb index f14f230..cfdb673 100644 --- a/lib/propane/grammar.rb +++ b/lib/propane/grammar.rb @@ -35,7 +35,7 @@ class Propane pattern = name end unless name =~ /^[a-zA-Z_][a-zA-Z_0-9]*$/ - raise Error.new("Invalid token name #{name}") + raise Error.new("Invalid token name #{name.inspect}") end @tokens << Token.new(name: name, pattern: pattern, id: @tokens.size, line_number: line_number) elsif sliced = input.slice!(/\Adrop\s+(\S+)\n/) @@ -43,8 +43,12 @@ class Propane @drop_tokens << Token.new(pattern: pattern, line_number: line_number) elsif sliced = input.slice!(/\A(\S+)\s*->\s*(.*?)(?:;|<<\n(.*?)^>>\n)/m) rule_name, components, code = $1, $2, $3 + unless rule_name =~ /^[a-zA-Z_][a-zA-Z_0-9]*$/ + raise Error.new("Invalid rule name #{name.inspect}") + end components = components.strip.split(/\s+/) - @rules << Rule.new(rule_name, components, code, line_number, @rules.size) + # Reserve rule ID 0 for the "real" start rule. + @rules << Rule.new(rule_name, components, code, line_number, @rules.size + 1) else if input.size > 25 input = input.slice(0..20) + "..." diff --git a/lib/propane/parser.rb b/lib/propane/parser.rb index 6149d37..829c39b 100644 --- a/lib/propane/parser.rb +++ b/lib/propane/parser.rb @@ -3,15 +3,13 @@ class Propane class Parser def initialize(start_rule_set) - @token_eof = Token.new(name: "$", id: TOKEN_EOF) + @eof_token = Token.new(name: "$", id: TOKEN_EOF) + start_rule = Rule.new("$$", [start_rule_set, @eof_token], nil, nil, 0) @item_sets = [] @item_sets_set = {} - start_items = start_rule_set.rules.map do |rule| - rule.components << @token_eof - Item.new(rule, 0) - end + start_item = Item.new(start_rule, 0) eval_item_sets = Set.new - eval_item_sets << ItemSet.new(start_items) + eval_item_sets << ItemSet.new([start_item]) while eval_item_sets.size > 0 this_eval_item_sets = eval_item_sets @@ -22,7 +20,7 @@ class Propane @item_sets << item_set @item_sets_set[item_set] = item_set item_set.following_symbols.each do |following_symbol| - unless following_symbol == @token_eof + unless following_symbol == @eof_token following_set = item_set.build_following_item_set(following_symbol) eval_item_sets << following_set end @@ -71,7 +69,7 @@ class Propane def process_item_set(item_set) item_set.following_symbols.each do |following_symbol| - unless following_symbol == @token_eof + unless following_symbol == @eof_token following_set = @item_sets_set[item_set.build_following_item_set(following_symbol)] item_set.following_item_set[following_symbol] = following_set following_set.in_sets << item_set