Skip to content

Commit

Permalink
Add more grammars
Browse files Browse the repository at this point in the history
* Option: ?
* Many: *
* Many1: +
* Grouping: ( ... )
  • Loading branch information
nurse committed Jun 18, 2023
1 parent 27512b6 commit aa88573
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 8 deletions.
75 changes: 75 additions & 0 deletions lib/racc/grammar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -787,6 +787,81 @@ def name
end


class OptionMark
def initialize(lineno)
@lineno = lineno
end

def name
'?'
end

alias inspect name

attr_reader :lineno
end


class ManyMark
def initialize(lineno)
@lineno = lineno
end

def name
'*'
end

alias inspect name

attr_reader :lineno
end


class Many1Mark
def initialize(lineno)
@lineno = lineno
end

def name
'+'
end

alias inspect name

attr_reader :lineno
end


class GroupStartMark
def initialize(lineno)
@lineno = lineno
end

def name
'('
end

alias inspect name

attr_reader :lineno
end


class GroupEndMark
def initialize(lineno)
@lineno = lineno
end

def name
')'
end

alias inspect name

attr_reader :lineno
end


class Prec
def initialize(symbol, lineno)
@symbol = symbol
Expand Down
118 changes: 110 additions & 8 deletions lib/racc/grammarfileparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,21 @@ module Racc
| seq("|") {|*|
OrMark.new(@scanner.lineno)
}\
| seq("?") {|*|
OptionMark.new(@scanner.lineno)
}\
| seq("*") {|*|
ManyMark.new(@scanner.lineno)
}\
| seq("+") {|*|
Many1Mark.new(@scanner.lineno)
}\
| seq("(") {|*|
GroupStartMark.new(@scanner.lineno)
}\
| seq(")") {|*|
GroupEndMark.new(@scanner.lineno)
}\
| seq("=", :symbol) {|_, sym|
Prec.new(sym, @scanner.lineno)
}\
Expand Down Expand Up @@ -210,27 +225,114 @@ def location
end

def add_rule_block(list)
sprec = nil
target = list.shift
case target
when OrMark, UserAction, Prec
when OrMark, OptionMark, ManyMark, Many1Mark, GroupStartMark, GroupEndMark, UserAction, Prec
raise CompileError, "#{target.lineno}: unexpected symbol #{target.name}"
end
enum = list.each.with_index
_, sym, idx = _add_rule_block(target, enum)
if idx
# sym is Racc::GroupEndMark
raise "#{sym.lineno}: unexpected symbol ')' at pos=#{idx}"
end
end

def _add_rule_block(target, enum)
rules = [] # [ [seqs, sprec], .. ]
curr = []
list.each do |i|
case i
sprec = nil
while (sym, idx = enum.next rescue nil)
case sym
when OrMark
add_rule target, curr, sprec
rules << [curr, sprec]
curr = []
sprec = nil
when OptionMark
curr << _add_option_rule(curr.pop)
when ManyMark
curr << _add_many_rule(curr.pop)
when Many1Mark
curr << _add_many1_rule(curr.pop)
when GroupStartMark
curr << _add_group_rule(enum)
when GroupEndMark
rules << [curr, sprec]
return rules, sym, idx
when Prec
raise CompileError, "'=<prec>' used twice in one rule" if sprec
sprec = i.symbol
sprec = sym.symbol
else
curr.push i
curr.push sym
end
end
rules << [curr, sprec]
rules.each do |syms, sprec|
add_rule target, syms, sprec
end
nil
end


def _add_option_rule(prev)
@option_rule_registry ||= {}
target = @option_rule_registry[prev.to_s]
return target if target
target = _gen_target_name("option", prev)
@option_rule_registry[prev.to_s] = target
act = UserAction.empty
@grammar.add Rule.new(target, [], act)
@grammar.add Rule.new(target, [prev], act)
target
end

def _add_many_rule(prev)
@many_rule_registry ||= {}
target = @many_rule_registry[prev.to_s]
return target if target
target = _gen_target_name("many", prev)
@many_rule_registry[prev.to_s] = target
src = SourceText.new("result = val", __FILE__, __LINE__)
act = UserAction.source_text(src)
@grammar.add Rule.new(target, [], act)
@grammar.add Rule.new(target, [prev, target], act)
target
end

def _add_many1_rule(prev)
@many1_rule_registry ||= {}
target = @many1_rule_registry[prev.to_s]
return target if target
target = _gen_target_name("many1", prev)
@many1_rule_registry[prev.to_s] = target
src = SourceText.new("result = val", __FILE__, __LINE__)
act = UserAction.source_text(src)
@grammar.add Rule.new(target, [prev], act)
@grammar.add Rule.new(target, [prev, target], act)
target
end

def _add_group_rule(enum)
target = @grammar.intern("-temp-group")
rules, _ = _add_rule_block(target, enum)
target_name = rules.map{|syms, sprec| syms.join("-")}.join("|")
@group_rule_registry ||= {}
unless target = @group_rule_registry[target_name]
target = @grammar.intern("-group@#{target_name}")
@group_rule_registry[target_name] = target
src = SourceText.new("result = val", __FILE__, __LINE__)
act = UserAction.source_text(src)
rules.each do |syms, sprec|
rule = Rule.new(target, syms, act)
rule.specified_prec = sprec
@grammar.add rule
end
end
add_rule target, curr, sprec
target
end

def _gen_target_name(type, sym)
@grammar.intern("-#{type}@#{sym.value}")
end

def add_rule(target, list, sprec)
Expand Down

0 comments on commit aa88573

Please sign in to comment.