class Yagg::Generator
Attributes
result[RW]
Public Class Methods
new(input)
click to toggle source
# File lib/yagg/gen.rb, line 7 def initialize(input) @input = input @indent = 0 self.result = "" end
Public Instance Methods
`(text)
click to toggle source
# File lib/yagg/gen.rb, line 35 def `(text) @result << make_indent(@indent, text) end
generate(under = "GG")
click to toggle source
# File lib/yagg/gen.rb, line 185 def generate(under = "GG") `module #{under}\n Scope = self\n` indent 2 generate_header generate_lexels generate_rules indent -2 `end\n` end
generate_header()
click to toggle source
# File lib/yagg/gen.rb, line 47 def generate_header <<~`EOF` class Lexel attr_accessor :value def values [value] end def typeid -1 end def initialize(value) raise TypeError unless self.class.check(value) if self.class === value self.value = value.value elsif Lexel === value || Rule === value raise TypeError else self.value = value end end def self.check(value) if Lexel === value || Rule === value return self === value end true end def to_text value.to_s end end Unchecked = Struct.new(:values, :typeid) class Rule attr_accessor :typeid, :values def to_text values.map{|x| x.to_text}.join end def initialize(*values) if values.length == 1 && Unchecked === values[0] self.values = values[0].values self.typeid = values[0].typeid else old = values typeid, values = self.class.check(values) raise TypeError, "\#{self.class.to_s}:can't find rule for \#{old}" unless typeid if typeid == -1 self.values = values[0].values self.typeid = values[0].typeid else self.values = values self.typeid = typeid end end end def self.grammel(a) case a when /^[A-Z]/ then Scope.const_get(a.upcase) when /^[a-z]/ then Scope.const_get(a.capitalize.gsub(/_([a-z])/){ $1.upcase }) when /^'(.)'/ then $1 else raise TypeError, "unknown grammar token \#{a}" end end def self.check_single(pattern, values) i = 0 j = 0 output = [] while i < values.length && j < pattern.length u = grammel(pattern[j]) if Class === u output << u.new(values[i]) else return nil if u != values[i] output << values[i] end i += 1 j += 1 end output rescue TypeError end def to_text self.values.map{|x| x.to_text}.join end def self.check_one(value, memo = {}) self::Includes.each{|x| next if memo[x] u = grammel(x) case u when String return value if u == value when lambda{|x| x < Lexel} return u.new(value) if u.check(value) else if u === value return u.new(Unchecked.new([value], -1)) else r = u.check_one(value, memo.update({u: 1})) return self.new(Unchecked.new([r], -1)) if r end end } nil end def self.check(values) if values.length == 1 if self === values[0] return -1, values elsif (r = check_one(values[0], {})) if self === r return -1, r.values else return -1, [r] end else return nil end return nil end self::Rules.each_with_index{|k, i| next if k.size != values.size r = check_single(k, values) return i, r if r } nil end end EOF end
generate_lexels()
click to toggle source
# File lib/yagg/gen.rb, line 13 def generate_lexels @input.tokens.each{|x| `#{x.upcase} = Class.new(Lexel)\n` } end
generate_rules()
click to toggle source
# File lib/yagg/gen.rb, line 26 def generate_rules @input.rules.each{|k, v| `class #{rule_name_case(k)} < Rule\n` ` Rules = #{v.select{|x| x.size != 1}.inspect}\n` ` Includes = #{v.select{|x| x.size == 1}.flatten}\n` `end\n` } end
indent(a = 0)
click to toggle source
# File lib/yagg/gen.rb, line 43 def indent(a = 0) @indent += a end
make_indent(num, text)
click to toggle source
# File lib/yagg/gen.rb, line 39 def make_indent(num, text) text.split(/(\n)/).map{|x| " "*num << x}.join end
Private Instance Methods
rule_name_case(str)
click to toggle source
# File lib/yagg/gen.rb, line 20 def rule_name_case(str) str.capitalize.gsub(/_([a-z])/){ $1.upcase } end