嘛,没啥东西可贴,就找找以前有没有什么好玩的东西出来吧 >_<
这个就是简单地把那种lisp括号表达式在Python中解析成字符串组成的元组。
能解析的格式被简化的很厉害,不仅是为了实现简单,也是确实让代码可以更简单一些。
用的LL的递归下降对字符解析,考虑到Python3有流IO,用那个会更好一些。
#! /usr/bin/env python26
# coding: utf-8
class SSexpr:
"""
A Simple Simplified Sexpr Reader.
@Author ee.zsy
@Date Mar.2012
type ssexpr = Symbol of string | Block of ssexpr list;
function parse : string - > ssexpr;
>>> parse(r'(1 2 "3\" 4"( 1 2 3))')
['1', '2', '3" 4', ['1', '2', '3']]
Notice that Python evaluates expressions from left to right.
"""
w = " \n\t"
e = " \n\t()[]"
b = (lambda i:lambda s,x:i(x).pop())(set(')]').difference)
m = 'Brackets or Parentheses do not match.'
a = dict(zip('\"\'nt\\','\"\'\n\t\\'))
f = 'Escape character is not recognized.'
def __init__(s,code):
s.s, s.p = code, 0
def read(s):
try:return s.exp()
except RuntimeError as e:raise SyntaxError(e)
@classmethod
def parse(c,code):
return c(code).read()
def peek(s):
return s.s[s.p] if s.p<len(s.s) else None
def eat(s):
s.p += 1;return s.s[s.p-1]
def exp(s,cm=0):
c = s.peek()
if c is None:return None
elif c in s.w:return s.eat() and s.exp()
elif c == '(':return s.eat() and s.blk(')')
elif c == '[':return s.eat() and s.blk(']')
elif c == '"':return s.eat() and s.str()
else:return s.sym()
def sym(s):
c = s.peek()
if c is None or c in s.e:return ""
else:return s.eat() and c+s.sym()
def str(s):
c = s.peek()
if c is None:raise EOFError
elif c == '"':return s.eat() and ''
elif c =='\\':return s.eat() and s.esc(s.eat())+s.str()
else:return s.eat() and c+s.str()
def esc(s,c):
if c in s.a:return s.a[c]
else:raise SyntaxError(s.f)
def blk(s,end):
c = s.peek()
if c is None:raise EOFError
elif c == s.b(end):raise SyntaxError(s.m)
elif c in s.w:return s.eat() and s.blk(end)
elif c == end:return s.eat() and tuple()
else:return tuple([s.exp()])+s.blk(end)
if 1:
assert SSexpr("""123 12""").read() == '123'
assert SSexpr("""(1 2 3 4(1 2 3))""").read() == ('1', '2', '3', '4', ('1', '2', '3'))
assert SSexpr("""(1 2 "3 4"( 1 2 3))""").read() == ('1', '2', '3 4', ('1', '2', '3'))
assert SSexpr.parse(r"""(1 2 "3\" 4"( 1 2 3))""") == ('1', '2', '3" 4', ('1', '2', '3'))
assert SSexpr.parse(r"""[]""") == tuple()
if __name__ == '__main__':
print SSexpr("""[hello world]""").read()
while 1:
print SSexpr(raw_input()).read()
再往前的一个功能略微多一点点的版本,有单独的正则表达式实现的词法解析部分。
#@Date Nov.27,2011
#@Author ee.zsy
import re
pattern = r'''
(?P<lpr>\()
|(?P<rpr>\))
|(?P<qte>\')
|(?P<qqt>`)
|(?P<uqs>,@)
|(?P<uqt>,)
|(?P<blt>\#[tT])
|(?P<blf>\#[fF])
|(?P<chr>\#\\.[^ \)\t\n\r]*)
|(?P<shr>\#)
|(?P<num>[-+]?(\d+(\.\d*)?|\.\d+)([eE][-+]?\d+)?)
|(?P<str>\"(\\.|[^"])*\")
|(?P<wht>([ \t\n\r]+)|(;.*?[\n\r]))
|(?P<sym>[^ ;\)\(\t\n\r]+)
'''
token = re.compile(pattern,re.S|re.X)
def peekToken(text,start=0):
regex = token.match(text,start)
if regex:
tag = [(k,v) for k,v in regex.groupdict().items() if v]
return tag[0],regex.end()
return None,None
然后余下的语法解析还是一样的了,只是情况相比要多一些。
不过代码代码不像这里这样简单的看的那么清爽,这里就不贴了。
虽然这里的东西都故意做了简化,但是改动之后倒是可以做表达式计算或者类AWK的解析什么的。
手写LL(1)的时候,有些左连接的操作符,要把循环的部分单独写一条规则出来。
比如像“num "+" num {"+" num}”这样的,要保证可以只根据下一个未处理的Token作出分支。
这里的这种情况有个专门的名词叫做什么什么来着的,囧死了人家都不知道了。
话说内部接口封装不够不可靠都很讨厌。
* Stack machine
这里先假设操作符都是二元的,那么最简单的一个前缀转后缀可以这么实现。
(define e '(+ (* 3 (- 2 3)) (+ 2 3)))
(define (t e) (if (pair? e) (let ((x (map t e))) (apply append (append (cdr x) (list (car x))))) (list e)))
(display (t e))
那么接下来,那么接下来就以后再写吧。