Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
ydah committed Dec 8, 2023
1 parent b35b7d6 commit c16e9c6
Show file tree
Hide file tree
Showing 11 changed files with 876 additions and 435 deletions.
11 changes: 10 additions & 1 deletion lib/lrama/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@
require "lrama/grammar/reference"
require "lrama/grammar/rule"
require "lrama/grammar/rule_builder"
require "lrama/grammar/parameterizing_rule_builder"
require "lrama/grammar/parameterizing_rule_resolver"
require "lrama/grammar/parameterizing_rule_rhs_builder"
require "lrama/grammar/parameterizing_rule"
require "lrama/grammar/symbol"
require "lrama/grammar/type"
require "lrama/grammar/union"
Expand Down Expand Up @@ -36,6 +40,7 @@ def initialize(rule_counter)
@rule_builders = []
@rules = []
@sym_to_rules = {}
@parameterizing_rule_resolver = ParameterizingRuleResolver.new
@empty_symbol = nil
@eof_symbol = nil
@error_symbol = nil
Expand Down Expand Up @@ -129,6 +134,10 @@ def add_rule_builder(builder)
@rule_builders << builder
end

def add_parameterizing_rule_builder(builder)
@parameterizing_rule_resolver.add_parameterizing_rule_builder(builder)
end

def prologue_first_lineno=(prologue_first_lineno)
@aux.prologue_first_lineno = prologue_first_lineno
end
Expand Down Expand Up @@ -310,7 +319,7 @@ def compute_first_set

def setup_rules
@rule_builders.each do |builder|
builder.setup_rules
builder.setup_rules(@parameterizing_rule_resolver)
end
end

Expand Down
12 changes: 12 additions & 0 deletions lib/lrama/grammar/parameterizing_rule.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Lrama
class Grammar
class ParameterizingRule < Struct.new(:name, :args, :rhs, keyword_init: true)
def ==(other)
self.class == other.class &&
self.name == other.name &&
self.args == other.args &&
self.rhs == other.rhs
end
end
end
end
38 changes: 38 additions & 0 deletions lib/lrama/grammar/parameterizing_rule_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
require 'lrama/grammar/parameterizing_rules/builder'

module Lrama
class Grammar
class ParameterizingRuleBuilder
attr_reader :name, :args, :rhs

def initialize(name, args, rhs)
@name = name
@args = args
@rhs = rhs
@required_args_count = args.count
end

def build_rules(token, build_token, rule_counter, lhs_tag, user_code, precedence_sym, line)
validate_argument_number!(token)
rules = []
@rhs.each do |rhs|
rules << Rule.new(id: rule_counter.increment, _lhs: build_token, _rhs: [rhs.symbol].compact, lhs_tag: lhs_tag, token_code: rhs.user_code, precedence_sym: rhs.precedence_sym, lineno: line)
end
rules
end

def build_token(token)
validate_argument_number!(token)
Lrama::Lexer::Token::Ident.new(s_value: "#{name}_#{token.args.first.s_value}")
end

private

def validate_argument_number!(token)
unless @required_args_count == token.args.count
raise "Invalid number of arguments. expect: #{@required_args_count} actual: #{token.args.count}"
end
end
end
end
end
32 changes: 32 additions & 0 deletions lib/lrama/grammar/parameterizing_rule_resolver.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
require 'lrama/grammar/parameterizing_rules/builder'

module Lrama
class Grammar
class ParameterizingRuleResolver
attr_reader :rules, :tokens

def initialize
@rules = []
@tokens = []
@parameterizing_rule_builders = []
end

def add_parameterizing_rule_builder(builder)
@parameterizing_rule_builders << builder
end

def defined?(name)
@parameterizing_rule_builders.any? { |builder| builder.name == name }
end

def build_rules(token, rule_counter, lhs_tag, user_code, precedence_sym, line)
@parameterizing_rule_builders.each do |builder|
build_token = builder.build_token(token)
@rules << builder.build_rules(token, build_token, rule_counter, lhs_tag, user_code, precedence_sym, line)
@tokens << build_token
end
@rules.flatten!
end
end
end
end
15 changes: 15 additions & 0 deletions lib/lrama/grammar/parameterizing_rule_rhs_builder.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
require 'lrama/grammar/parameterizing_rules/builder'

module Lrama
class Grammar
class ParameterizingRuleRhsBuilder
attr_accessor :symbol, :user_code, :precedence_sym

def initialize
@symbol = nil
@user_code = nil
@precedence_sym = nil
end
end
end
end
24 changes: 17 additions & 7 deletions lib/lrama/grammar/rule_builder.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ def complete_input
freeze_rhs
end

def setup_rules
def setup_rules(parameterizing_rules_resolver = nil)
preprocess_references unless @skip_preprocess_references
process_rhs
process_rhs(parameterizing_rules_resolver)
build_rules
end

Expand Down Expand Up @@ -97,7 +97,7 @@ def build_rules

# rhs is a mixture of variety type of tokens like `Ident`, `Parameterizing`, `UserCode` and so on.
# `#process_rhs` replaces some kind of tokens to `Ident` so that all `@replaced_rhs` are `Ident` or `Char`.
def process_rhs
def process_rhs(parameterizing_rules_resolver)
return if @replaced_rhs

@replaced_rhs = []
Expand All @@ -110,11 +110,21 @@ def process_rhs
when Lrama::Lexer::Token::Ident
@replaced_rhs << token
when Lrama::Lexer::Token::Parameterizing
parameterizing = ParameterizingRules::Builder.new(token, @rule_counter, @lhs_tag, user_code, precedence_sym, line)
parameterizing.build.each do |r|
@parameterizing_rules << r
if parameterizing_rules_resolver.defined?(token.s_value)
parameterizing_rules_resolver.build_rules(token, @rule_counter, @lhs_tag, user_code, precedence_sym, line)
parameterizing_rules_resolver.rules.each do |r|
@parameterizing_rules << r
end
parameterizing_rules_resolver.tokens.each do |t|
@replaced_rhs << t
end
else
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
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
1 change: 1 addition & 0 deletions lib/lrama/lexer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ class Lexer
%error-token
%empty
%code
%rule
)

def initialize(text)
Expand Down
Loading

0 comments on commit c16e9c6

Please sign in to comment.