Lrama v0.5.11

This commit is contained in:
yui-knk 2023-12-01 18:02:56 +09:00 committed by Yuichiro Kaneko
parent 818813c2bd
commit 9f6c6f88c3
21 changed files with 540 additions and 437 deletions

View File

@ -13,6 +13,5 @@ require "lrama/report"
require "lrama/state" require "lrama/state"
require "lrama/states" require "lrama/states"
require "lrama/states_reporter" require "lrama/states_reporter"
require "lrama/type"
require "lrama/version" require "lrama/version"
require "lrama/warning" require "lrama/warning"

View File

@ -9,9 +9,9 @@ require "lrama/grammar/reference"
require "lrama/grammar/rule" require "lrama/grammar/rule"
require "lrama/grammar/rule_builder" require "lrama/grammar/rule_builder"
require "lrama/grammar/symbol" require "lrama/grammar/symbol"
require "lrama/grammar/type"
require "lrama/grammar/union" require "lrama/grammar/union"
require "lrama/lexer" require "lrama/lexer"
require "lrama/type"
module Lrama module Lrama
# Grammar is the result of parsing an input grammar file # Grammar is the result of parsing an input grammar file
@ -148,7 +148,7 @@ module Lrama
def prepare def prepare
normalize_rules normalize_rules
collect_symbols collect_symbols
replace_token_with_symbol set_lhs_and_rhs
fill_symbol_number fill_symbol_number
fill_default_precedence fill_default_precedence
fill_sym_to_rules fill_sym_to_rules
@ -391,6 +391,11 @@ module Lrama
@rules << rule @rules << rule
end 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| builder.midrule_action_rules.each do |rule|
add_nterm(id: rule._lhs) add_nterm(id: rule._lhs)
end end
@ -484,7 +489,7 @@ module Lrama
end end
end end
def replace_token_with_symbol def set_lhs_and_rhs
@rules.each do |rule| @rules.each do |rule|
rule.lhs = token_to_symbol(rule._lhs) if rule._lhs rule.lhs = token_to_symbol(rule._lhs) if rule._lhs

View File

@ -50,7 +50,7 @@ module Lrama
end end
def lhs def lhs
(@rule.original_rule || @rule).lhs @rule.lhs
end end
def raise_tag_not_found_error(ref) def raise_tag_not_found_error(ref)

View File

@ -8,6 +8,7 @@ require 'lrama/grammar/parameterizing_rules/builder/separated_list'
module Lrama module Lrama
class Grammar class Grammar
class ParameterizingRules class ParameterizingRules
# Builder for parameterizing rules
class Builder class Builder
RULES = { RULES = {
option: Lrama::Grammar::ParameterizingRules::Builder::Option, option: Lrama::Grammar::ParameterizingRules::Builder::Option,
@ -20,23 +21,39 @@ module Lrama
separated_list: Lrama::Grammar::ParameterizingRules::Builder::SeparatedList, 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 @token = token
@key = token.s_value.to_sym @key = token.s_value.to_sym
@rule_counter = rule_counter @rule_counter = rule_counter
@lhs = lhs @lhs_tag = lhs_tag
@user_code = user_code @user_code = user_code
@precedence_sym = precedence_sym @precedence_sym = precedence_sym
@line = line @line = line
@builder = nil
end end
def build def build
if RULES.key?(@key) create_builder
RULES[@key].new(@token, @rule_counter, @lhs, @user_code, @precedence_sym, @line).build @builder.build
else end
raise "Parameterizing rule does not exist. `#{@key}`"
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
end end
def validate_key!
raise "Parameterizing rule does not exist. `#{@key}`" unless RULES.key?(@key)
end
end end
end end
end end

View File

@ -2,16 +2,24 @@ module Lrama
class Grammar class Grammar
class ParameterizingRules class ParameterizingRules
class Builder class Builder
# Base class for parameterizing rules builder
class Base 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 @args = token.args
@token = @args.first @token = @args.first
@rule_counter = rule_counter @rule_counter = rule_counter
@lhs = lhs @lhs_tag = lhs_tag
@user_code = user_code @user_code = user_code
@precedence_sym = precedence_sym @precedence_sym = precedence_sym
@line = line @line = line
@expected_argument_num = 1 @expected_argument_num = 1
@build_token = nil
end
def build
raise NotImplementedError
end end
private private

View File

@ -2,15 +2,23 @@ module Lrama
class Grammar class Grammar
class ParameterizingRules class ParameterizingRules
class Builder class Builder
# Builder for list of general parameterizing rules
class List < Base class List < Base
# program: list(number)
#
# =>
#
# program: list_number
# list_number: ε
# list_number: list_number number
def build def build
validate_argument_number! validate_argument_number!
rules = [] rules = []
list_token = Lrama::Lexer::Token::Ident.new(s_value: "list_#{@token.s_value}") @build_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: @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: list_token, _rhs: [], 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 << Rule.new(id: @rule_counter.increment, _lhs: list_token, _rhs: [list_token, @token], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line)
rules rules
end end
end end

View File

@ -2,15 +2,23 @@ module Lrama
class Grammar class Grammar
class ParameterizingRules class ParameterizingRules
class Builder class Builder
# Builder for nonempty list of general parameterizing rules
class NonemptyList < Base class NonemptyList < Base
# program: nonempty_list(number)
#
# =>
#
# program: nonempty_list_number
# nonempty_list_number: number
# nonempty_list_number: nonempty_list_number number
def build def build
validate_argument_number! validate_argument_number!
rules = [] rules = []
nonempty_list_token = Lrama::Lexer::Token::Ident.new(s_value: "nonempty_list_#{@token.s_value}") @build_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: @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: nonempty_list_token, _rhs: [@token], 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 << 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)
rules rules
end end
end end

View File

@ -2,15 +2,23 @@ module Lrama
class Grammar class Grammar
class ParameterizingRules class ParameterizingRules
class Builder class Builder
# Builder for option of general parameterizing rules
class Option < Base class Option < Base
# program: option(number)
#
# =>
#
# program: option_number
# option_number: ε
# option_number: number
def build def build
validate_argument_number! validate_argument_number!
rules = [] rules = []
option_token = Lrama::Lexer::Token::Ident.new(s_value: "option_#{@token.s_value}") @build_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: @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: option_token, _rhs: [], 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 << Rule.new(id: @rule_counter.increment, _lhs: option_token, _rhs: [@token], token_code: @ser_code, precedence_sym: @precedence_sym, lineno: @line)
rules rules
end end
end end

View File

@ -2,23 +2,34 @@ module Lrama
class Grammar class Grammar
class ParameterizingRules class ParameterizingRules
class Builder class Builder
# Builder for separated list of general parameterizing rules
class SeparatedList < Base 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 super
@separator = @args[0] @separator = @args[0]
@token = @args[1] @token = @args[1]
@expected_argument_num = 2 @expected_argument_num = 2
end 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 def build
validate_argument_number! validate_argument_number!
rules = [] rules = []
separated_list_token = Lrama::Lexer::Token::Ident.new(s_value: "separated_list_#{@token.s_value}") @build_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) 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: separated_list_token, _rhs: [], token_code: @user_code, precedence_sym: @precedence_sym, lineno: @line) 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: separated_list_token, _rhs: [@token], 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_list_token, _rhs: [separated_list_token, @separator, @token], 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 rules
end end
end end

View File

@ -2,22 +2,29 @@ module Lrama
class Grammar class Grammar
class ParameterizingRules class ParameterizingRules
class Builder class Builder
# Builder for separated nonempty list of general parameterizing rules
class SeparatedNonemptyList < Base 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 super
@separator = @args[0] @separator = @args[0]
@token = @args[1] @token = @args[1]
@expected_argument_num = 2 @expected_argument_num = 2
end 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 def build
validate_argument_number! validate_argument_number!
rules = [] rules = []
separated_list_token = Lrama::Lexer::Token::Ident.new(s_value: "separated_nonempty_list_#{@token.s_value}") @build_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: @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: separated_list_token, _rhs: [@token], 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 << 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)
rules rules
end end
end end

View File

@ -1,12 +1,13 @@
module Lrama module Lrama
class Grammar class Grammar
# _rhs holds original RHS element. Use rhs to refer to Symbol. # _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 attr_accessor :original_rule
def ==(other) def ==(other)
self.class == other.class && self.class == other.class &&
self.lhs == other.lhs && self.lhs == other.lhs &&
self.lhs_tag == other.lhs_tag &&
self.rhs == other.rhs && self.rhs == other.rhs &&
self.token_code == other.token_code && self.token_code == other.token_code &&
self.position_in_original_rule_rhs == other.position_in_original_rule_rhs && self.position_in_original_rule_rhs == other.position_in_original_rule_rhs &&

View File

@ -3,7 +3,7 @@ require 'lrama/grammar/parameterizing_rules/builder'
module Lrama module Lrama
class Grammar class Grammar
class RuleBuilder class RuleBuilder
attr_accessor :lhs, :line attr_accessor :lhs, :lhs_tag, :line
attr_reader :rhs, :user_code, :precedence_sym attr_reader :rhs, :user_code, :precedence_sym
def initialize(rule_counter, midrule_action_counter, position_in_original_rule_rhs = nil, skip_preprocess_references: false) def initialize(rule_counter, midrule_action_counter, position_in_original_rule_rhs = nil, skip_preprocess_references: false)
@ -14,6 +14,7 @@ module Lrama
@lhs = nil @lhs = nil
@rhs = [] @rhs = []
@lhs_tag = nil
@user_code = nil @user_code = nil
@precedence_sym = nil @precedence_sym = nil
@line = nil @line = nil
@ -81,22 +82,16 @@ module Lrama
def build_rules def build_rules
tokens = @replaced_rhs tokens = @replaced_rhs
# Expand Parameterizing rules rule = Rule.new(
if tokens.any? {|r| r.is_a?(Lrama::Lexer::Token::Parameterizing) } id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, token_code: user_code,
@rules = @parameterizing_rules position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line
@midrule_action_rules = [] )
else @rules = [rule]
rule = Rule.new( @midrule_action_rules = @rule_builders_for_derived_rules.map do |rule_builder|
id: @rule_counter.increment, _lhs: lhs, _rhs: tokens, token_code: user_code, rule_builder.rules
position_in_original_rule_rhs: @position_in_original_rule_rhs, precedence_sym: precedence_sym, lineno: line end.flatten
) @midrule_action_rules.each do |r|
@rules = [rule] r.original_rule = 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 end
end end
@ -115,8 +110,11 @@ module Lrama
when Lrama::Lexer::Token::Ident when Lrama::Lexer::Token::Ident
@replaced_rhs << token @replaced_rhs << token
when Lrama::Lexer::Token::Parameterizing when Lrama::Lexer::Token::Parameterizing
@parameterizing_rules = ParameterizingRules::Builder.new(token, @rule_counter, lhs, user_code, precedence_sym, line).build parameterizing = ParameterizingRules::Builder.new(token, @rule_counter, @lhs_tag, user_code, precedence_sym, line)
@replaced_rhs << token parameterizing.build.each do |r|
@parameterizing_rules << r
end
@replaced_rhs << parameterizing.build_token
when Lrama::Lexer::Token::UserCode when Lrama::Lexer::Token::UserCode
prefix = token.referred ? "@" : "$@" prefix = token.referred ? "@" : "$@"
new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s) new_token = Lrama::Lexer::Token::Ident.new(s_value: prefix + @midrule_action_counter.increment.to_s)

View File

@ -6,10 +6,23 @@
module Lrama module Lrama
class Grammar class Grammar
class Symbol < Struct.new(:id, :alias_name, :number, :tag, :term, :token_id, :nullable, :precedence, :printer, :error_token, keyword_init: true) class Symbol
attr_accessor :first_set, :first_set_bitmap attr_accessor :id, :alias_name, :tag, :number, :token_id, :nullable, :precedence, :printer, :error_token, :first_set, :first_set_bitmap
attr_reader :term
attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol attr_writer :eof_symbol, :error_symbol, :undef_symbol, :accept_symbol
def initialize(id:, alias_name: nil, number: nil, tag: nil, term:, token_id: nil, nullable: nil, precedence: nil, printer: nil)
@id = id
@alias_name = alias_name
@number = number
@tag = tag
@term = term
@token_id = token_id
@nullable = nullable
@precedence = precedence
@printer = printer
end
def term? def term?
term term
end end
@ -41,6 +54,7 @@ module Lrama
# name for yysymbol_kind_t # name for yysymbol_kind_t
# #
# See: b4_symbol_kind_base # See: b4_symbol_kind_base
# @type var name: String
def enum_name def enum_name
case case
when accept_symbol? when accept_symbol?

View File

@ -0,0 +1,6 @@
module Lrama
class Grammar
class Type < Struct.new(:id, :tag, keyword_init: true)
end
end
end

View File

@ -157,8 +157,7 @@ module Lrama
while !@scanner.eos? do while !@scanner.eos? do
case case
when @scanner.scan(/\n/) when @scanner.scan(/\n/)
@line += 1 newline
@head = @scanner.pos + 1
when @scanner.scan(/\*\//) when @scanner.scan(/\*\//)
return return
else else

View File

@ -1,8 +1,21 @@
require 'lrama/lexer/token/char'
require 'lrama/lexer/token/ident'
require 'lrama/lexer/token/parameterizing'
require 'lrama/lexer/token/tag'
require 'lrama/lexer/token/user_code'
module Lrama module Lrama
class Lexer class Lexer
class Token < Struct.new(:s_value, :alias_name, :location, keyword_init: true) class Token
attr_reader :s_value, :location
attr_accessor :alias_name, :referred
attr_accessor :referred def initialize(s_value:, alias_name: nil, location: nil)
s_value.freeze
@s_value = s_value
@alias_name = alias_name
@location = location
end
def to_s def to_s
"#{super} location: #{location}" "#{super} location: #{location}"
@ -36,9 +49,3 @@ module Lrama
end end
end end
end end
require 'lrama/lexer/token/char'
require 'lrama/lexer/token/ident'
require 'lrama/lexer/token/parameterizing'
require 'lrama/lexer/token/tag'
require 'lrama/lexer/token/user_code'

View File

@ -4,7 +4,7 @@ module Lrama
class Parameterizing < Token class Parameterizing < Token
attr_accessor :args attr_accessor :args
def initialize(s_value: nil, alias_name: nil, location: nil, args: []) def initialize(s_value:, alias_name: nil, location: nil, args: [])
super s_value: s_value, alias_name: alias_name, location: location super s_value: s_value, alias_name: alias_name, location: location
@args = args @args = args
end end

File diff suppressed because it is too large Load Diff

View File

@ -1,4 +0,0 @@
module Lrama
class Type < Struct.new(:id, :tag, keyword_init: true)
end
end

View File

@ -1,3 +1,3 @@
module Lrama module Lrama
VERSION = "0.5.10".freeze VERSION = "0.5.11".freeze
end end

View File

@ -72,7 +72,6 @@
<%- if output.aux.prologue -%> <%- if output.aux.prologue -%>
/* First part of user prologue. */ /* First part of user prologue. */
#line <%= output.aux.prologue_first_lineno %> "<%= output.grammar_file_path %>" #line <%= output.aux.prologue_first_lineno %> "<%= output.grammar_file_path %>"
<%= output.aux.prologue %> <%= output.aux.prologue %>
#line [@oline@] [@ofile@] #line [@oline@] [@ofile@]
<%- end -%> <%- end -%>
@ -2048,7 +2047,6 @@ yyreturnlab:
<%# b4_percent_code_get([[epilogue]]) -%> <%# b4_percent_code_get([[epilogue]]) -%>
<%- if output.aux.epilogue -%> <%- if output.aux.epilogue -%>
#line <%= output.aux.epilogue_first_lineno - 1 %> "<%= output.grammar_file_path %>" #line <%= output.aux.epilogue_first_lineno - 1 %> "<%= output.grammar_file_path %>"
<%= output.aux.epilogue -%> <%= output.aux.epilogue -%>
<%- end -%> <%- end -%>