Experiments with ruby-processing (processing-2.2.1) and JRubyArt for processing-3.0

Tuesday, 29 January 2013

Adding requirements rspec

In my previous post I presented an initial specification for my lsystems csgrammar parser. That is the most basic form, in which context is given by the preceding or following token in the axiom/production. Here is the specification of a more complicated parser that can take an ignore string, that includes those tokens that should be ignored wrt context. Typically the tokens will represent special instructions to interpreter such as [ and ] which mean push/pop matrix etc.
require 'CSLSystem'

IGNORE = 'ignore'

describe "LSystem" do
  context "given axiom 'biaaaaaa'" do
    context "with function a=b if context, ignoring IGNORE" do
      describe "#generate" do
        it "should equal 'biaaaaaa' at zero iteration" do
          LSystem.new('biaaaaaa', {'b' => 'a', 'b<a' => 'b'}, IGNORE).generate(0).should == 'biaaaaaa'
        end
        it "should equal 'aibaaaaa' after one iteration" do
          LSystem.new('biaaaaaa', {'b' => 'a', 'b<a' => 'b'}, IGNORE).generate(1).should == 'aibaaaaa'
        end
        it "should equal 'aiabaaaa' after one iteration" do
          LSystem.new('aibaaaaa', {'b' => 'a', 'b<a' => 'b'}, IGNORE).generate(1).should == 'aiabaaaa'
        end
        it "should equal 'aiabaaaa' after two iterations" do
          LSystem.new('biaaaaaa', {'b' => 'a', 'b<a' => 'b'}, IGNORE).generate(2).should == 'aiabaaaa'
        end
        it "should equal 'aiaabaaa' after three iteration" do
          LSystem.new('biaaaaaa', {'b' => 'a', 'b<a' => 'b'}, IGNORE).generate(3).should == 'aiaabaaa'
        end
        it "should equal 'aiaaaaba' after five iteration" do
          LSystem.new('biaaaaaa', {'b' => 'a', 'b<a' => 'b'}, IGNORE).generate(5).should == 'aiaaaaba'
        end
        it "should equal 'biaaaaaa' after seven iterations" do
          LSystem.new('biaaaaaa', {'b' => 'a', 'b<a' => 'b'}, IGNORE).generate(7).should == 'biaaaaaa'
        end
      end
    end
  end
end


Here is the revised grammar parser:-
######################################
# cs_grammar.rb a context sensitive
# 1-L lsystem grammar for 
# ruby/ruby-processing
# by Martin Prout (January 2013)
######################################



##################################
# The grammar class stores rules
# in two Hashes, one for cs rules,
# one for context free rules. Rules
# are filtered on input, and context
# is checked using get_rule in production
##################################

class LSystem

  attr_reader :axiom, :context, :no_context, :idx, :ignore
  def initialize(axiom, rules, ignore)
    @axiom = axiom
    @no_context = {}
    @context = {}
    @ignore = ignore
    rules.each_pair do |pair|
      add_rule pair[0], pair[1]
    end
  end

  def add_rule(pre, rule)
    if pre.length == 3
      if pre[1] == '<'
        @context[pre[2]] = pre
      elsif pre[1] == '>'
        @context[pre[0]] = pre
      end
      @no_context[pre] = rule # key length == 3
    elsif pre.length == 1
      @no_context[pre] = rule # key length == 1
    else
      print "unrecognized grammar '#{pre}'"
    end
  end

  def generate(repeat = 0) # repeat iteration grammar rules
    prod = axiom
    repeat.times do
      prod = new_production(prod)
    end
    return prod
  end


  def new_production prod  # single iteration grammar rules
    @idx = -1
    prod.gsub!(/./) do |ch|
      get_rule(prod, ch)
    end
  end

  def get_rule prod, ch
    rule = ch # default is return original character as rule (no change)
    @idx += 1 # increment the index of axiom/production as a side effect
    if (context.has_key?(ch))
      if context[ch][1] == '<'
        cs_char = context[ch][0]
        rule = no_context[context[ch]] if cs_char == get_context(prod, idx, -1) # use context sensitive rule
      elsif context[ch][1] == '>'
        cs_char = context[ch][2]
        rule = no_context[context[ch]] if cs_char == get_context(prod, idx, 1) # use context sensitive rule
      end
    else
      rule = no_context[ch] if no_context.has_key?(ch) # context free rule if it exists
    end
    return rule
  end

  def get_context prod, idx, inc
    index = idx + inc
    while (ignore.include? prod[index])
      index += inc
    end
    return prod[index]
  end
end

No comments:

Post a Comment

Followers

About Me

My photo
I have developed JRubyArt and propane new versions of ruby-processing for JRuby-9.1.5.0 and processing-3.2.2