[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Pingus-CVS] r3475 - trunk/sexpr
From: |
grumbel at BerliOS |
Subject: |
[Pingus-CVS] r3475 - trunk/sexpr |
Date: |
Sat, 3 Nov 2007 08:18:35 +0100 |
Author: grumbel
Date: 2007-11-03 08:18:34 +0100 (Sat, 03 Nov 2007)
New Revision: 3475
Added:
trunk/sexpr/level-syntax.scm
trunk/sexpr/parser.rb
Modified:
trunk/sexpr/schema.rb
trunk/sexpr/sexpr.rb
trunk/sexpr/sexpr_test.rb
Log:
- some more cleanup
Added: trunk/sexpr/level-syntax.scm
===================================================================
--- trunk/sexpr/level-syntax.scm 2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/level-syntax.scm 2007-11-03 07:18:34 UTC (rev 3475)
@@ -0,0 +1,50 @@
+;; -*- scheme -*-
+
+(element (name "pingus-level")
+ (use "required")
+ (type (mapping
+ (children
+ (element (name "version") (type (int)))
+ (element (name "head")
+ (type (mapping
+ (children
+ (element (name "levelname") (type (string)))
+ (element (name "description") (type (string)))
+ (element (name "author") (type (string)))
+ (element (name "number-of-pingus") (type (int)))
+ (element (name "number-to-save") (type (int)))
+ (element (name "time") (type (int)))
+ (element (name "difficulty") (type (int)))
+ (element (name "playable") (type (int)))
+ (element (name "comment") (type (string)))
+ (element (name "music") (type (string)))
+ (element (name "actions")
+ (type (mapping
+ (children
+ (element (name "basher") (type (int (min 1))))
+ (element (name "blocker") (type (int (min 1))))
+ (element (name "bomber") (type (int (min 1))))
+ (element (name "bridger") (type (int (min 1))))
+ (element (name "climber") (type (int (min 1))))
+ (element (name "jumper") (type (int (min 1))))
+ ))))
+ ))))
+ (element (name "objects")
+ (type (sequence
+ (children
+ (element (name "groundpiece")
+ (type (mapping
+ (children
+ (element (name "position") (type (vector2i)))
+ (element (name "surface") (type (surface)))))))
+
+ (element (name "exit")
+ (type (mapping
+ (children
+ (element (name "position") (type (vector2i)))
+ (element (name "surface") (type (surface)))
+ (element (name "release-rate") (type (int)))))))
+ ))))
+ ))))
+
+;; EOF ;;
Added: trunk/sexpr/parser.rb
===================================================================
--- trunk/sexpr/parser.rb 2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/parser.rb 2007-11-03 07:18:34 UTC (rev 3475)
@@ -0,0 +1,276 @@
+# SExpr - A simple Ruby library for parsing and validating s-expressions
+# Copyright (C) 2007 Ingo Ruhnke <address@hidden>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+require "sexpr.rb"
+
+module SExpr
+ class Parser
+
+ 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 initialize(str)
+ @str = str
+ end
+
+ def parse()
+ @state = :look_for_token
+ tokenize()
+
+ elements = []
+ sublists = []
+
+ @tokens.each{ |token|
+ if token.is_a?(SExpr) then
+ if not sublists.empty? then
+ sublists.last().append(token)
+ else
+ elements << token
+ end
+ elsif token.is_a?(Array) then
+ if token[0] == :list_start then
+ sublists.push(List.new([], token[1]))
+ elsif token[0] == :list_end then
+ if sublists.empty? then
+ raise "Unexpected List end"
+ else
+ lst = sublists.pop()
+ if not sublists.empty? then
+ sublists.last().append(lst)
+ else
+ elements << lst
+ end
+ end
+ end
+ else
+ raise "Parser bug: parse: #{token}"
+ end
+ }
+
+ return elements
+ end
+
+ def tokenize()
+ @line = 1
+ @column = 1
+
+ @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
+ if @token_start == @pos - 1 and not is_digit(@address@hidden) then
+ raise "address@hidden:address@hidden:
'address@hidden@token_start].chr}' must be followed by digit"
+ else
+ submit(:integer, false)
+ end
+ 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[1..-2].
+ gsub("\\n", "\n").
+ gsub("\\\"", "\"").
+ gsub("\\t", "\t"),
+ get_pos())
+
+ when :symbol
+ @tokens << Symbol.new(current_token, get_pos())
+
+ when :list_start
+ @tokens << [:list_start, get_pos()]
+
+ when :list_end
+ @tokens << [:list_end, get_pos()]
+
+ when :comment
+ # ignore
+
+ when :whitespace
+ # ignore
+
+ else
+ raise "Parser Bug: #{type}"
+ end
+ # puts "#{current_token.inspect} => #{type} :
address@hidden:address@hidden"
+ end
+ end
+end
+
+# EOF #
Modified: trunk/sexpr/schema.rb
===================================================================
--- trunk/sexpr/schema.rb 2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/schema.rb 2007-11-03 07:18:34 UTC (rev 3475)
@@ -15,8 +15,10 @@
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+require "sexpr.rb"
+require "parser.rb"
+
module SExpr
-
class Schema
def initialize(schema)
if schema.is_a?(SExpr) then
@@ -31,6 +33,50 @@
end
end
+ class Element
+ attr_reader :name # name of the expected element
+ attr_reader :use # required, optional, forbidden
+ attr_reader :type # ListType, IntegerType, ...
+
+ def validate(sexpr)
+ if not sexpr.is_a?(List) then
+ raise "#{sexpr.pos}: expected list, got #{sexpr.class}"
+ else
+ if sexpr.value.empty() then
+ raise "#{sexpr.pos}: expected a non-empty List"
+ else
+ if not sexpr[0].is_a?(Symbol) then
+ raise "#{sexpr.pos}: expected a symbol, got #{sexpr[0].class}"
+ else
+ if sexpr[0].value != @name then
+ raise "#{sexpr.pos}: expected symbol '#{name}', got
#{sexpr[0].value}"
+ else
+ # ok, now check type and/or validate children
+
+ end
+ end
+ end
+ end
+ end
+ end
+
+ class IntegerType
+
+ end
+
+ # A list of ((key value) ...)
+ class MappingType
+
+ end
+
+ # A list of other elements ((foo 5) (bar 10) (baz "foo") ...)
+ class SequenceType
+
+ end
+
+ class ChoiceType
+
+ end
end
# EOF #
Modified: trunk/sexpr/sexpr.rb
===================================================================
--- trunk/sexpr/sexpr.rb 2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/sexpr.rb 2007-11-03 07:18:34 UTC (rev 3475)
@@ -16,262 +16,12 @@
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
module SExpr
- class Parser
- 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 initialize(str)
- @str = str
- end
-
- def parse()
- @state = :look_for_token
- tokenize()
-
- elements = []
- sublists = []
-
- @tokens.each{ |token|
- if token.is_a?(SExpr) then
- if not sublists.empty? then
- sublists.last().append(token)
- else
- elements << token
- end
- elsif token.is_a?(Array) then
- if token[0] == :list_start then
- sublists.push(List.new([], token[1]))
- elsif token[0] == :list_end then
- if sublists.empty? then
- raise "Unexpected List end"
- else
- lst = sublists.pop()
- if not sublists.empty? then
- sublists.last().append(lst)
- else
- elements << lst
- end
- end
- end
- else
- raise "Parser bug: parse: #{token}"
- end
- }
-
- return elements
- end
-
- def tokenize()
- @line = 1
- @column = 1
-
- @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
- if @token_start == @pos - 1 and not is_digit(@address@hidden) then
- raise "address@hidden:address@hidden:
'address@hidden@token_start].chr}' must be followed by digit"
- else
- submit(:integer, false)
- end
- 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[1..-2].
- gsub("\\n", "\n").
- gsub("\\\"", "\"").
- gsub("\\t", "\t"),
- get_pos())
-
- when :symbol
- @tokens << Symbol.new(current_token, get_pos())
-
- when :list_start
- @tokens << [:list_start, get_pos()]
-
- when :list_end
- @tokens << [:list_end, get_pos()]
-
- 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
+ attr_reader :pos
+
def initialize(pos = nil)
+ @pos = pos
end
def self.parse(str)
@@ -375,6 +125,14 @@
@value << el
end
+ def [](idx)
+ return @value[idx]
+ end
+
+ def empty?()
+ return @value.empty?()
+ end
+
def to_s()
return "(" + @value.map{|i| i.to_s}.join(" ") + ")"
end
Modified: trunk/sexpr/sexpr_test.rb
===================================================================
--- trunk/sexpr/sexpr_test.rb 2007-11-03 06:53:45 UTC (rev 3474)
+++ trunk/sexpr/sexpr_test.rb 2007-11-03 07:18:34 UTC (rev 3475)
@@ -1,6 +1,7 @@
#!/usr/bin/ruby -w
require "sexpr.rb"
+require "parser.rb"
if ARGV.empty?() then
puts SExpr::SExpr.parse("(pi8ngulevel -.51 a (b +1.5) -5)")
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Pingus-CVS] r3475 - trunk/sexpr,
grumbel at BerliOS <=