[Top][All Lists]
[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
+ *
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Pingus-CVS] r3467 - trunk/pingus/contrib,
grumbel at BerliOS <=