pingus-cvs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Pingus-CVS] r3467 - trunk/pingus/contrib


From: grumbel at BerliOS
Subject: [Pingus-CVS] r3467 - trunk/pingus/contrib
Date: Fri, 2 Nov 2007 17:32:05 +0100

Author: grumbel
Date: 2007-11-02 17:32:04 +0100 (Fri, 02 Nov 2007)
New Revision: 3467

Added:
   trunk/pingus/contrib/sexpr.rb
Log:
- wrote a Ruby Sexpr parser

Added: trunk/pingus/contrib/sexpr.rb
===================================================================
--- trunk/pingus/contrib/sexpr.rb       2007-11-02 09:23:24 UTC (rev 3466)
+++ trunk/pingus/contrib/sexpr.rb       2007-11-02 16:32:04 UTC (rev 3467)
@@ -0,0 +1,353 @@
+#!/usr/bin/ruby -w
+
+module SExpr
+
+  class Lexer
+    attr_reader :tokens
+
+    def initialize(str)
+      @state = :look_for_token
+      # puts str.inspect
+      # puts
+      lex(str)
+    end
+
+    def is_digit(c)
+      return (?0..?9).member?(c)
+    end
+
+    def is_letter(c)
+      return((?a..?z).member?(c) or (?A..?Z).member?(c))
+    end
+
+    def is_whitespace(c)
+      return(c == ?\s or c == ?\n or c == ?\t)
+    end
+
+    def is_special_initial(c)
+      return(c == ?! or
+             c == ?$ or 
+             c == ?% or 
+             c == ?& or 
+             c == ?* or 
+             c == ?/ or 
+             c == ?: or 
+             c == ?< or 
+             c == ?= or 
+             c == ?> or 
+             c == ?? or 
+             c == ?^ or 
+             c == ?_ or 
+             c == ?~)
+    end
+
+    def is_special_subsequent(c)
+      return(c == ?+ or
+             c == ?- or
+             c == ?. or
+             c == ?@)
+    end
+
+    def is_sign(c)
+      return(c == ?+ or
+             c == ?-)
+    end
+
+    def parse()
+      elements = []
+      sublists = []
+
+      @tokens.each{ |token|
+        if token == :list_start then
+          sublists.push(List.new([], nil))
+        elsif token == :list_end then
+          if sublists.empty? then
+            raise "Unexpected List end"
+          else
+            elements << sublists.pop
+          end
+        elsif token.is_a?(SExpr) then
+          if not sublists.empty? then
+            sublists.last().append(token)
+          else
+            elements << token
+          end
+        else
+          raise "Parser bug: parse: #{token}"
+        end
+      }
+
+      return elements
+    end
+
+    def lex(str)
+      @line   = 1
+      @column = 1
+      @str = str
+      @last_c = nil
+      @tokens = []
+
+      @pos = 0
+      @token_start = @pos
+      
+      @advance = true
+      while(@pos < str.length) do
+        @c = address@hidden
+
+        scan(@c)
+        
+        if @advance then
+          # Line/Column counting
+          if (@c == ?\n) then
+            @line   += 1
+            @column  = 1
+          else
+            @column += 1
+          end
+
+          @last_c = @c
+
+          @pos += 1
+        else
+          @advance = true
+        end
+      end
+
+      scan(nil) # EOF #
+    end
+
+    def scan(c)
+      case @state
+      when :look_for_token:
+          if is_digit(c) or is_sign(c) then
+            @state = :parse_integer_or_real
+          elsif c == ?\" then
+            @state = :parse_string
+          elsif c == ?# then
+            @state = :parse_boolean
+          elsif is_letter(c) or is_special_initial(c) then
+            @state = :parse_symbol
+          elsif is_whitespace(c) then
+            @state = :parse_whitespace
+          elsif c == ?; then
+            @state = :parse_comment
+          elsif c == ?) then
+            submit(:list_end, true)
+          elsif c == ?( then
+            submit(:list_start, true)
+          elsif c == nil then
+            # EOF is ok
+          else
+            raise "address@hidden:address@hidden: unexpected character 
'#{c.chr}'"
+          end
+
+      when :parse_integer_or_real:
+          if is_digit(c) then
+            # ok
+          elsif c == ?. then
+            @state = :parse_real
+          else
+            submit(:integer, false)
+          end
+
+      when :parse_boolean:
+          if c == ?t or c == ?f then
+            submit(:boolean, true)
+          else
+            raise "address@hidden:address@hidden: expected 'f' or 't', got 
'#{c.chr}"
+          end
+
+      when :parse_real:
+          if (?0..?9).member?(c) then
+            # ok
+          else
+            submit(:real, false)
+          end
+
+      when :parse_symbol:
+          if is_letter(c) or is_digit(c) or is_special_subsequent(c) or 
is_special_initial(c) then
+            # ok
+          else
+            submit(:symbol, false)
+          end
+        
+      when :parse_string:
+          if (c == ?" and @last_c != ?\\) then
+            submit(:string, true)
+          end
+
+      when :parse_whitespace
+        if not is_whitespace(c) then
+          submit(:whitespace, false)
+        end
+
+      when :parse_comment
+        if c == ?\n then
+          submit(:comment, true)
+        end     
+
+      else
+        raise "Parser error, unknown state: address@hidden"
+      end
+    end
+
+    def get_pos()
+      return "@line:@column"
+    end
+
+    def submit(type, include_current_character)
+      @state = :look_for_token
+
+      if include_current_character then
+        current_token = @address@hidden(@pos)]
+        @token_start = @pos+1
+      else
+        current_token = @address@hidden(@pos-1)]
+        @token_start = @pos
+        @advance = false
+      end
+      
+      case type
+      when :boolean
+        @tokens << Boolean.new(current_token == "#t", get_pos())
+        
+      when :integer
+        @tokens << Integer.new(current_token.to_i, get_pos())
+
+      when :real
+        @tokens << Real.new(current_token.to_f, get_pos())
+
+      when :string
+        @tokens << String.new(current_token.
+                              gsub("\\n", "\n").
+                              gsub("\\\"", "\"").
+                              gsub("\\t", "\t"),
+                              get_pos())
+
+      when :symbol
+        @tokens << Symbol.new(current_token, get_pos())
+        
+      when :list_start
+        @tokens << :list_start
+
+      when :list_end
+        @tokens << :list_end
+
+      when :comment
+        # ignore
+
+      when :whitespace
+        # ignore
+
+      else
+        raise "Parser Bug: #{type}" 
+      end
+      # puts "#{current_token.inspect} => #{type} : 
address@hidden:address@hidden"
+    end
+  end
+
+  class SExpr
+    def initialize(pos = nil)
+    end
+  end
+
+  # Boolean
+  class Boolean < SExpr
+    attr_reader :value
+
+    def initialize(value, pos)
+      super(pos)
+      @value = value
+    end
+
+    def to_s()
+      return @value.to_s
+    end
+  end
+
+  # 1025
+  class Integer < SExpr
+    attr_reader :value
+
+    def initialize(value, pos)
+      super(pos)
+      @value = value
+    end
+
+    def to_s()
+      return @value.to_s
+    end
+  end
+
+  # 5.1
+  class Real < SExpr
+    attr_reader :value
+
+    def initialize(value, pos)
+      super(pos)
+      @value = value
+    end
+
+    def to_s()
+      return @value.to_s
+    end
+  end
+
+  # "foo"
+  class String < SExpr
+    attr_reader :value
+
+    def initialize(value, pos = nil)
+      super(pos)
+      @value = value
+    end
+
+    def to_s()
+      return @value.to_s
+    end
+  end
+
+  # foo
+  class Symbol < SExpr
+    attr_reader :value
+
+    def initialize(value, pos = nil)
+      super(pos)
+      @value = value
+    end
+
+    def to_s()
+      return @value.to_s
+    end
+  end
+
+  # (foo bar baz)
+  class List < SExpr
+    attr_reader :children  
+
+    def initialize(value, pos = nil)
+      super(pos)
+      @value = value
+    end
+
+    def append(el)
+      @value << el
+    end
+
+    def to_s()
+      return "(" + @value.map{|i| i.to_s}.join(" ") + ")"
+    end
+  end
+end
+
+if ARGV.empty?() then
+  lexer = SExpr::Lexer.new("a (b 1.5)")
+  puts lexer.parse()
+else
+  ARGV.each{|filename|
+    lexer = SExpr::Lexer.new(File.new(filename).read())
+    puts lexer.parse()
+  }
+end
+
+# EOF #


Property changes on: trunk/pingus/contrib/sexpr.rb
___________________________________________________________________
Name: svn:executable
   + *





reply via email to

[Prev in Thread] Current Thread [Next in Thread]