root/lang/ruby/LoLS/trunk/lols.rb @ 31217

Revision 31217, 3.9 kB (checked in by kiyoka, 4 years ago)

Added new project "LoLS"

  • Property svn:executable set to *
Line 
1#!/usr/bin/env ruby
2#
3# Lisp Of Least Surprise (for Rubyist)
4#
5#
6require 'stringio'
7require 'pp'
8
9class Cell
10  NIL=:nil
11  def initialize( car = NIL, cdr = NIL )
12    @car = car
13    @cdr = cdr
14  end
15  attr_accessor :car, :cdr
16end
17
18
19class Token
20  def initialize( type, str )
21    @type = type
22    @str  = str
23  end
24  attr_accessor :type, :str
25end
26
27
28class Reader
29  ## tokens
30  T_EOF       = :t_eof
31  T_LPAREN    = :t_lparen
32  T_RPAREN    = :t_rparen
33  T_SYMBOL    = :t_symbol
34  T_NUM       = :t_num
35  T_QUOTE     = :t_quote
36  T_DOT       = :t_dot
37
38  # inport is IO class
39  def initialize( inport )
40    @inport   = inport
41    @curtoken = nil
42  end
43
44  def skipspace
45    ch = @inport.getc
46    if !@inport.eof?
47      while ch.chr.match( /[ \t\r\n]/ )
48        ch = @inport.getc
49      end
50      @inport.ungetc( ch )
51    end
52  end
53
54  def readwhile( exp )
55    ret = ""
56    while true
57      ch = @inport.getc
58      if @inport.eof?
59        break
60      end
61      if ch.chr.match( exp )
62        ret += ch.chr
63      else
64        @inport.ungetc( ch )
65        break
66      end
67    end
68    ret
69  end
70
71  def token
72    skipspace
73    ch = @inport.getc
74    if @inport.eof?
75      @curtoken = Token.new( T_EOF, "" )
76    else
77      str = ch.chr
78      type =
79        case str
80        when '('
81          T_LPAREN
82        when ')'
83          T_RPAREN
84        when '.'
85          T_DOT
86        when /[a-zA-Z+*\/=!-]/ # symbol
87          str += readwhile( /[a-zA-Z+*\/=!-]/ )
88          T_SYMBOL
89        when /[0-9]/        # number
90          str += readwhile( /[0-9.]/ )
91          T_NUM
92        when /[\']/
93          T_QUOTE
94        end
95      p "  [" + str + "] : " + type.to_s
96      @curtoken = Token.new( type, str )
97    end
98  end
99
100  def curtoken
101    @curtoken
102  end
103
104  def atom( tok )
105    case tok.type
106    when T_SYMBOL
107      tok.str
108    when T_NUM
109      tok.str.to_i
110    when T_QUOTE
111      "quote"
112    end
113  end
114
115  def sexp( tok )
116    dotted = false
117    cells = []
118    while true
119      case tok.type
120      when T_EOF
121        print "Error: unbalanced paren(2)"
122        break
123      when T_LPAREN
124        cells << Cell.new( sexp( token ))
125        tok = curtoken
126      when T_RPAREN
127        token
128        break
129      else
130        if tok.type == T_DOT
131          if 1 == cells.size
132            dotted = true
133            tok = token
134          else
135            print "Error : illegal dotted pair syntax"
136            break
137          end
138        elsif tok.type == T_QUOTE
139          cells << Cell.new( atom( tok ), top( token ))
140          tok = curtoken
141        else
142          cells << Cell.new( atom( tok ))
143          tok = token
144        end
145      end
146    end
147    if dotted
148      ## dotted list
149      Cell.new( cells[0].car, cells[1].car )
150    else
151      ## setup list
152      if 1 < cells.size
153        ptr = cells.pop
154        cells.reverse.each { |x|
155          x.cdr = ptr
156          ptr = x
157        }
158      end
159      cells.first
160    end
161  end
162  def top( tok )
163    case tok.type
164    when T_EOF
165      break
166    when T_LPAREN
167      sexp( token )
168    when T_RPAREN
169      print "Error: unbalanced paren(1)"
170    when T_QUOTE
171      Cell.new( atom( tok ), top( token ))
172    else
173      atom( tok )
174    end
175  end
176
177  def read
178    top( token )
179  end
180end
181
182
183class Core
184  def initialize( io )
185    @reader       = Reader.new( io )
186    @evalulator   = Evalulator.new
187    @printer      = Printer.new
188  end
189 
190  def repl
191    while true
192      @printer.print( @evalulator.eval( @reader.read ))
193    end
194  end
195end
196
197
198# test
199def readerTest( sexp )
200  sio = StringIO.open( sexp )
201  reader = Reader.new( sio )
202  p "--- " + sexp + " --- is "
203  pp reader.read
204end
205
206readerTest( " + " )
207readerTest( " 123 " )
208readerTest( " ( 1 . 2 ) " )
209readerTest( " ( 1 ) " )
210readerTest( " (car '(1 . 2)) " )
211readerTest( " (cdr '(1 . 2)) " )
212readerTest( " ( 1 2 3 4 ) " )
213readerTest( " '( 1 2 3 '4 ) " )
214#readerTest( " (( 1 )) " )
215#readerTest( " ( 1 2 ( 3 4 )) " )
216#readerTest( " ( " )
217#readerTest( " ) " )
218
219
220#def main
221#  sio = StringIO.open( " (car 1 2 3) " )
222#  core = Core.new( sio )
223#  while true
224#    core.repl
225#  end
226#end
Note: See TracBrowser for help on using the browser.