# -*- Mode: Python; tab-width: 4 -*- import string import sys class lisp_reader: # input buffering def __init__ (self, socket): self.socket = socket self.buffer = '' self.pos = 0 def refill (self): self.buffer = self.socket.recv (8192) if not self.buffer: raise EOFError else: self.pos = 0 def read_exact (self, size): left = len(self.buffer) - self.pos if size < left: result = self.buffer[self.pos:self.pos+size] self.pos += size return result else: result = self.buffer[self.pos:] + self.socket.recv_exact (size - left) self.buffer = '' self.pos = 0 return result def peek (self): if (not self.buffer) or (self.pos >= len(self.buffer)): self.refill() return self.buffer[self.pos] def next (self): if (not self.buffer) or (self.pos >= len(self.buffer)): self.refill() self.pos += 1 return self.buffer[self.pos - 1] # form reader def skip_whitespace (self): while 1: ch = self.peek() if not ch: break elif ch not in string.whitespace: # comments? if ch == ';': while self.next() not in '\r\n': pass else: break else: self.next() def read (self): self.skip_whitespace() ch = self.peek() if ch == '': raise EOFError, "Unexpected end of file" elif ch == '(': return self.read_list() elif ch == '"': return self.read_string() elif ch == "'": self.next() return [('symbol', 'quote'), self.read()] elif ch in '-0123456789': a = self.read_atom() if a == '-': # bad, bad, bad return ('symbol', '-') all_digits = 1 for ch in a: if ch not in '-0123456789': all_digits = 0 break if all_digits: return int (a) else: return ('atom', a) elif ch == '\r': if self.read() != '\n': raise "Syntax Error" else: return else: atom = self.read_atom() if atom == 'NIL': return ('nil') else: return ('atom', atom) def read_atom (self): # read at least one character result = self.next() while 1: ch = self.peek() if ch in string.whitespace or ch in '()': return result else: result = result + self.next() def read_string (self): result = '' # thow away the quote. ch = self.next() while 1: ch = self.peek() if ch == '"': # throw away the close-quote ch = self.next() return ('string', result) else: result = result + self.next() def read_list (self): result = [] # throw away the paren paren = self.next() while 1: self.skip_whitespace() p = self.peek() if p == ')': # throw away the paren ch = self.next() return result else: x = self.read () result.append(x) def read_all (self): forms = [] try: while 1: form = self.read() forms.append (form) except EOFError: return forms if __name__ == '__main__': import pprint import sys if len (sys.argv) < 2: file = sys.stdin else: file = open (sys.argv[1], 'r') p = reader (file) pprint.pprint (p.read_all())