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/states"
require "lrama/states_reporter"
require "lrama/type"
require "lrama/version"
require "lrama/warning"

View File

@ -9,9 +9,9 @@ require "lrama/grammar/reference"
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
@ -148,7 +148,7 @@ module Lrama
def prepare
normalize_rules
collect_symbols
replace_token_with_symbol
set_lhs_and_rhs
fill_symbol_number
fill_default_precedence
fill_sym_to_rules
@ -391,6 +391,11 @@ module Lrama
@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
@ -484,7 +489,7 @@ module Lrama
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

View File

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

View File

@ -8,6 +8,7 @@ require 'lrama/grammar/parameterizing_rules/builder/separated_list'
module Lrama
class Grammar
class ParameterizingRules
# Builder for parameterizing rules
class Builder
RULES = {
option: Lrama::Grammar::ParameterizingRules::Builder::Option,
@ -20,23 +21,39 @@ module Lrama
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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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 &&

View File

@ -3,7 +3,7 @@ require 'lrama/grammar/parameterizing_rules/builder'
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)
@ -14,6 +14,7 @@ module Lrama
@lhs = nil
@rhs = []
@lhs_tag = nil
@user_code = nil
@precedence_sym = nil
@line = nil
@ -81,22 +82,16 @@ module Lrama
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
@ -115,8 +110,11 @@ module Lrama
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)

View File

@ -6,10 +6,23 @@
module Lrama
class Grammar
class Symbol < Struct.new(:id, :alias_name, :number, :tag, :term, :token_id, :nullable, :precedence, :printer, :error_token, keyword_init: true)
attr_accessor :first_set, :first_set_bitmap
class Symbol
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
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?
term
end
@ -41,6 +54,7 @@ module Lrama
# name for yysymbol_kind_t
#
# See: b4_symbol_kind_base
# @type var name: String
def enum_name
case
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
case
when @scanner.scan(/\n/)
@line += 1
@head = @scanner.pos + 1
newline
when @scanner.scan(/\*\//)
return
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
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
"#{super} location: #{location}"
@ -36,9 +49,3 @@ module Lrama
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
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
@args = args
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
VERSION = "0.5.10".freeze
VERSION = "0.5.11".freeze
end

View File

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