Skip to content

Commit

Permalink
Lrama v0.5.11
Browse files Browse the repository at this point in the history
  • Loading branch information
yui-knk committed Dec 1, 2023
1 parent 818813c commit 9f6c6f8
Show file tree
Hide file tree
Showing 21 changed files with 526 additions and 423 deletions.
1 change: 0 additions & 1 deletion tool/lrama/lib/lrama.rb
Expand Up @@ -13,6 +13,5 @@
require "lrama/state"
require "lrama/states"
require "lrama/states_reporter"
require "lrama/type"
require "lrama/version"
require "lrama/warning"
11 changes: 8 additions & 3 deletions tool/lrama/lib/lrama/grammar.rb
Expand Up @@ -9,9 +9,9 @@
require "lrama/grammar/rule"
require "lrama/grammar/rule_builder"
require "lrama/grammar/symbol"
require "lrama/grammar/type"
require "lrama/grammar/union"
require "lrama/lexer"
require "lrama/type"

module Lrama
# Grammar is the result of parsing an input grammar file
Expand Down Expand Up @@ -148,7 +148,7 @@ def epilogue=(epilogue)
def prepare
normalize_rules
collect_symbols
replace_token_with_symbol
set_lhs_and_rhs
fill_symbol_number
fill_default_precedence
fill_sym_to_rules
Expand Down Expand Up @@ -391,6 +391,11 @@ def normalize_rules
@rules << rule
end

builder.parameterizing_rules.each do |rule|
add_nterm(id: rule._lhs, tag: rule.lhs_tag)
@rules << rule
end

builder.midrule_action_rules.each do |rule|
add_nterm(id: rule._lhs)
end
Expand Down Expand Up @@ -484,7 +489,7 @@ def fill_symbol_number
end
end

def replace_token_with_symbol
def set_lhs_and_rhs
@rules.each do |rule|
rule.lhs = token_to_symbol(rule._lhs) if rule._lhs

Expand Down
2 changes: 1 addition & 1 deletion tool/lrama/lib/lrama/grammar/code/rule_action.rb
Expand Up @@ -50,7 +50,7 @@ def rhs
end

def lhs
(@rule.original_rule || @rule).lhs
@rule.lhs
end

def raise_tag_not_found_error(ref)
Expand Down
29 changes: 23 additions & 6 deletions tool/lrama/lib/lrama/grammar/parameterizing_rules/builder.rb
Expand Up @@ -8,6 +8,7 @@
module Lrama
class Grammar
class ParameterizingRules
# Builder for parameterizing rules
class Builder
RULES = {
option: Lrama::Grammar::ParameterizingRules::Builder::Option,
Expand All @@ -20,23 +21,39 @@ class Builder
separated_list: Lrama::Grammar::ParameterizingRules::Builder::SeparatedList,
}

def initialize(token, rule_counter, lhs, user_code, precedence_sym, line)
def initialize(token, rule_counter, lhs_tag, user_code, precedence_sym, line)
@token = token
@key = token.s_value.to_sym
@rule_counter = rule_counter
@lhs = lhs
@lhs_tag = lhs_tag
@user_code = user_code
@precedence_sym = precedence_sym
@line = line
@builder = nil
end

def build
if RULES.key?(@key)
RULES[@key].new(@token, @rule_counter, @lhs, @user_code, @precedence_sym, @line).build
else
raise "Parameterizing rule does not exist. `#{@key}`"
create_builder
@builder.build
end

def build_token
create_builder
@builder.build_token
end

private

def create_builder
unless @builder
validate_key!
@builder = RULES[@key].new(@token, @rule_counter, @lhs_tag, @user_code, @precedence_sym, @line)
end
end

def validate_key!
raise "Parameterizing rule does not exist. `#{@key}`" unless RULES.key?(@key)
end
end
end
end
Expand Down
12 changes: 10 additions & 2 deletions tool/lrama/lib/lrama/grammar/parameterizing_rules/builder/base.rb
Expand Up @@ -2,16 +2,24 @@ module Lrama
class Grammar
class ParameterizingRules
class Builder
# Base class for parameterizing rules builder
class Base
def initialize(token, rule_counter, lhs, user_code, precedence_sym, line)
attr_reader :build_token

def initialize(token, rule_counter, lhs_tag, user_code, precedence_sym, line)
@args = token.args
@token = @args.first
@rule_counter = rule_counter
@lhs = lhs
@lhs_tag = lhs_tag
@user_code = user_code
@precedence_sym = precedence_sym
@line = line
@expected_argument_num = 1
@build_token = nil
end

def build
raise NotImplementedError
end

private
Expand Down
16 changes: 12 additions & 4 deletions tool/lrama/lib/lrama/grammar/parameterizing_rules/builder/list.rb
Expand Up @@ -2,15 +2,23 @@ module Lrama
class Grammar
class ParameterizingRules
class Builder
# Builder for list of general parameterizing rules
class List < Base

# program: list(number)
#
# =>
#
# program: list_number
# list_number: ε
# list_number: list_number number
def build
validate_argument_number!

rules = []
list_token = Lrama::Lexer::Token::Ident.new(s_value: "list_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @lhs, _rhs: [list_token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: list_token, _rhs: [], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: list_token, _rhs: [list_token, @token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
@build_token = Lrama::Lexer::Token::Ident.new(s_value: "list_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [@build_token, @token], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules
end
end
Expand Down
Expand Up @@ -2,15 +2,23 @@ module Lrama
class Grammar
class ParameterizingRules
class Builder
# Builder for nonempty list of general parameterizing rules
class NonemptyList < Base

# program: nonempty_list(number)
#
# =>
#
# program: nonempty_list_number
# nonempty_list_number: number
# nonempty_list_number: nonempty_list_number number
def build
validate_argument_number!

rules = []
nonempty_list_token = Lrama::Lexer::Token::Ident.new(s_value: "nonempty_list_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @lhs, _rhs: [nonempty_list_token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: nonempty_list_token, _rhs: [@token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: nonempty_list_token, _rhs: [nonempty_list_token, @token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
@build_token = Lrama::Lexer::Token::Ident.new(s_value: "nonempty_list_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [@token], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [@build_token, @token], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules
end
end
Expand Down
Expand Up @@ -2,15 +2,23 @@ module Lrama
class Grammar
class ParameterizingRules
class Builder
# Builder for option of general parameterizing rules
class Option < Base

# program: option(number)
#
# =>
#
# program: option_number
# option_number: ε
# option_number: number
def build
validate_argument_number!

rules = []
option_token = Lrama::Lexer::Token::Ident.new(s_value: "option_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @lhs, _rhs: [option_token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: option_token, _rhs: [], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: option_token, _rhs: [@token], token_code: @ser_code, precedence_sym: @precedence_sym, lineno: @line)
@build_token = Lrama::Lexer::Token::Ident.new(s_value: "option_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [@token], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules
end
end
Expand Down
Expand Up @@ -2,23 +2,34 @@ module Lrama
class Grammar
class ParameterizingRules
class Builder
# Builder for separated list of general parameterizing rules
class SeparatedList < Base
def initialize(token, rule_counter, lhs, user_code, precedence_sym, line)
def initialize(token, rule_counter, lhs_tag, user_code, precedence_sym, line)
super
@separator = @args[0]
@token = @args[1]
@expected_argument_num = 2
end

# program: separated_list(',', number)
#
# =>
#
# program: separated_list_number
# separated_list_number: ε
# separated_list_number: separated_nonempty_list_number
# separated_nonempty_list_number: number
# separated_nonempty_list_number: separated_nonempty_list_number ',' number
def build
validate_argument_number!

rules = []
separated_list_token = Lrama::Lexer::Token::Ident.new(s_value: "separated_list_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @lhs, _rhs: [separated_list_token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: separated_list_token, _rhs: [], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: separated_list_token, _rhs: [@token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: separated_list_token, _rhs: [separated_list_token, @separator, @token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
@build_token = Lrama::Lexer::Token::Ident.new(s_value: "separated_list_#{@token.s_value}")
separated_nonempty_list_token = Lrama::Lexer::Token::Ident.new(s_value: "separated_nonempty_list_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [separated_nonempty_list_token], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: separated_nonempty_list_token, _rhs: [@token], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: separated_nonempty_list_token, _rhs: [separated_nonempty_list_token, @separator, @token], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules
end
end
Expand Down
Expand Up @@ -2,22 +2,29 @@ module Lrama
class Grammar
class ParameterizingRules
class Builder
# Builder for separated nonempty list of general parameterizing rules
class SeparatedNonemptyList < Base
def initialize(token, rule_counter, lhs, user_code, precedence_sym, line)
def initialize(token, rule_counter, lhs_tag, user_code, precedence_sym, line)
super
@separator = @args[0]
@token = @args[1]
@expected_argument_num = 2
end

# program: separated_nonempty_list(',', number)
#
# =>
#
# program: separated_nonempty_list_number
# separated_nonempty_list_number: number
# separated_nonempty_list_number: separated_nonempty_list_number ',' number
def build
validate_argument_number!

rules = []
separated_list_token = Lrama::Lexer::Token::Ident.new(s_value: "separated_nonempty_list_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @lhs, _rhs: [separated_list_token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: separated_list_token, _rhs: [@token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: separated_list_token, _rhs: [separated_list_token, @separator, @token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
@build_token = Lrama::Lexer::Token::Ident.new(s_value: "separated_nonempty_list_#{@token.s_value}")
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [@token], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules << Rule.new(id: @rule_counter.increment, _lhs: @build_token, _rhs: [@build_token, @separator, @token], lhs_tag: @lhs_tag, token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules
end
end
Expand Down
3 changes: 2 additions & 1 deletion tool/lrama/lib/lrama/grammar/rule.rb
@@ -1,12 +1,13 @@
module Lrama
class Grammar
# _rhs holds original RHS element. Use rhs to refer to Symbol.
class Rule < Struct.new(:id, :_lhs, :lhs, :_rhs, :rhs, :token_code, :position_in_original_rule_rhs, :nullable, :precedence_sym, :lineno, keyword_init: true)
class Rule < Struct.new(:id, :_lhs, :lhs, :lhs_tag, :_rhs, :rhs, :token_code, :position_in_original_rule_rhs, :nullable, :precedence_sym, :lineno, keyword_init: true)
attr_accessor :original_rule

def ==(other)
self.class == other.class &&
self.lhs == other.lhs &&
self.lhs_tag == other.lhs_tag &&
self.rhs == other.rhs &&
self.token_code == other.token_code &&
self.position_in_original_rule_rhs == other.position_in_original_rule_rhs &&
Expand Down
36 changes: 17 additions & 19 deletions tool/lrama/lib/lrama/grammar/rule_builder.rb
Expand Up @@ -3,7 +3,7 @@
module Lrama
class Grammar
class RuleBuilder
attr_accessor :lhs, :line
attr_accessor :lhs, :lhs_tag, :line
attr_reader :rhs, :user_code, :precedence_sym

def initialize(rule_counter, midrule_action_counter, position_in_original_rule_rhs = nil, skip_preprocess_references: false)
Expand All @@ -14,6 +14,7 @@ def initialize(rule_counter, midrule_action_counter, position_in_original_rule_r

@lhs = nil
@rhs = []
@lhs_tag = nil
@user_code = nil
@precedence_sym = nil
@line = nil
Expand Down Expand Up @@ -81,22 +82,16 @@ def preprocess_references
def build_rules
tokens = @replaced_rhs

# Expand Parameterizing rules
if tokens.any? {|r| r.is_a?(Lrama::Lexer::Token::Parameterizing) }
@rules = @parameterizing_rules
@midrule_action_rules = []
else
rule = Rule.new(
id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, token_code: user_code,
position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line
)
@rules = [rule]
@midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
rule_builder.rules
end.flatten
@midrule_action_rules.each do |r|
r.original_rule = rule
end
rule = Rule.new(
id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, token_code: user_code,
position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line
)
@rules = [rule]
@midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
rule_builder.rules
end.flatten
@midrule_action_rules.each do |r|
r.original_rule = rule
end
end

Expand All @@ -115,8 +110,11 @@ def process_rhs
when Lrama::Lexer::Token::Ident
@replaced_rhs << token
when Lrama::Lexer::Token::Parameterizing
@parameterizing_rules = ParameterizingRules::Builder.new(token, @rule_counter, lhs, user_code, precedence_sym, line).build
@replaced_rhs << token
parameterizing = ParameterizingRules::Builder.new(token, @rule_counter, @lhs_tag, user_code, precedence_sym, line)
parameterizing.build.each do |r|
@parameterizing_rules << r
end
@replaced_rhs << parameterizing.build_token
when Lrama::Lexer::Token::UserCode
prefix = token.referred ? "@" : "$@"
new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)
Expand Down

0 comments on commit 9f6c6f8

Please sign in to comment.