|
锁定老贴子 主题:rparsec
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
|---|---|
| 作者 | 正文 |
|
时间:2006-10-05
正在ruby上写parsec,发现语法比java好到不能行。虽然还没有全部完成。
大家看看下面计算器的例子。(为什么不用eval?这个parsec的目的是general purpose的parser framework,要支持自己做dsl的,不是仅仅ruby parser。calculator只是一个测试。) 支持+,-,*,/,括号等
require 'src/functors'
require 'src/parsers'
class CalculatorTestCase < RUNIT::TestCase
include Functors
include Parsers
def operator(op, val)
str(op) >> value(val)
end
def calculator
int = integer.map(&To_i)
ops = OperatorTable.new.
prefix(operator('-', Neg), 60).
infixl(operator('+', Plus), 20).
infixl(operator('-', Minus), 20).
infixl(operator('*', Mul), 40).
infixl(operator('/', Div), 40)
expr = nil
term = int | char('(') >> lazy{expr} << char(')')
delim = whitespace.many_
expr = delim >> Expressions.build(term, ops, delim)
end
def testCalculator
assert_equal(5, calculator.parse('1 + 2 * (5 + -3)'))
end
end
声明:JavaEye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
|
|
| 返回顶楼 | |
|
时间:2006-10-06
这个就看糊涂了,ajoo上仙啥时候给俺们讲解一下Haskell天书之parsec篇?
|
|
| 返回顶楼 | |
|
时间:2006-10-06
稍微解释一下。
rparsec的基本操作都是在Parser上面。 char(?a)是一个Parser,它只parse一个单一的'a'字符,并且返回这个字符。 str('abc')是一个Parser,它parse一个'abc'字符串,并且返回这个字符串。 value(1)是一个Parser,它不管输入,直接返回1。 eof是一个Parser,它要求输入当前必须是空。 parser1 | parser2 是一个parser,它在parser1失败之后跑parser2。 parser1 >> parser2 是一个parser,它在parser1成功后,接着跑parser2。 parser1 << parser2 是一个parser。他也是顺序跑parser1和parser2,但是保留parser1的计算结果。 parser.many是一个parser,它相当于bnf里面的kleen star。就是说重复0..n次。把结果存在一个数祖里面。 parser.many_和many类似。不过它只保留最后一次的结果。 parser.map{...} 是一个parser,它先执行parser,产生的结果用一个block变换。 OperatorTable用来声明操作符的结合率和优先级。 Expression.build用来根据操作符的结合率和优先级,以及原子表达式,产生一个能够parse完整表达式的parser。 差不多了八? scip的第二章有关于closure property的描述,这个parsec系统就有closure property:操作的参数是Parser,结果也是Parser。 |
|
| 返回顶楼 | |
|
时间:2006-10-09
发布了:
http://jparsec.codehaus.org/Ruby+Parsec |
|
| 返回顶楼 | |
|
时间:2006-10-09
我比较喜欢这样的写法^_^:
class OperatorTable
def OperatorTable.new
o = allocate
yield o
o
end
...
end
ops = OperatorTable.new do |o|
o.prefix(operator('-', Neg), 60)
o.infixl(operator('+', Plus), 20)
o.infixl(operator('-', Minus), 20)
o.infixl(operator('*', Mul), 40)
o.infixl(operator('/', Div), 40)
end
|
|
| 返回顶楼 | |
|
时间:2006-10-09
好主意!改好了。多谢。
不过,这样重复写"o.",真的更好么? |
|
| 返回顶楼 | |
|
时间:2006-10-09
还有,这样做和:
ops = OperatorTable.new
ops.prefix(operator('-', Neg), 60)
ops.infixl(operator('+', Plus), 20)
ops.infixl(operator('-', Minus), 20)
ops.infixl(operator('*', Mul), 40)
ops.infixl(operator('/', Div), 40)
相比有什么好处? |
|
| 返回顶楼 | |
|
时间:2006-10-10
一般block方式封装的话是为了在block之前之后插点什么逻辑进去,比如exception处理啦。。。否则就无所谓,对象方式也很直观。原来的串串烧(decorator)模式串的东西小点写在一行还好,串好几个大蹄膀分成多行就难看了点。还有种省点括号更函数化点的风格:
# '<<' => prefix, '<|' => infixl
ops = OperatorTable.new
ops << operator('-', Neg), 60
ops <| operator('+', Plus), 20
ops <| operator('-', Minus), 20
ops <| operator('*', Mul), 40
ops <| operator('/', Div), 40
|
|
| 返回顶楼 | |
|
时间:2006-10-10
<|是一个合法运算符么?
有一点觉得不爽.象SomeClass.new {|this|...} 这种用法,为什么需要我自己写def new才行?为什么ruby不直接支持这个idiom? |
|
| 返回顶楼 | |
|
时间:2006-10-10
失败orz, yy代码的结果,自挂东南枝去。。。
改用<=巴 不支持大概是因为这个idiom还不够通用,也不明显节省代码。 |
|
| 返回顶楼 | |







