From: ara.t.howard@... Date: 2006-06-06T00:31:13+09:00 Subject: Re: parsing a boolean expression On Mon, 5 Jun 2006, Daniel Baird wrote: > Hmm.. I haven't done anything with yacc before, and my expressions _are_ > going to be pretty simple, so I guess your advice is to write it myself :) > > I'd kinda fancied returning a tree made up of nodes that are either: > > - a token > - a list of nodes with a common operator > > eg "A and ( B or C or D) and E" would be: > > node0: AND(A, node1, E) > node1: OR(B, C, D) > > It's not a binary tree but it would be somewhat convenient for the > processing / storing / re-displaying I need to do.. I just hoped I'd save a > day or two standing on someone else's shoulders. > > Thanks Matthew. > > ;D this is extremely short and relatively secure, it may fit depending on your use case and leverages the fact that ruby knows how to parse ruby: harp:~ > cat a.rb class BoolExp attr 'exp' attr 'value' def initialize exp, context = {} @exp = exp.to_s tokens = context.keys.map{|k| k.to_s}.join '|' re = %r/^(?:\s*|#{ tokens }|[)(]|and|or|not)+$/i raise "bad exp <#{ @exp }>" unless @exp =~ re @value = Thread.new(exp, context) do |e, c| $SAFE = 4 Module.new do sc = class << self self end c.each do |k,v| case k.to_s when %r/^[A-Z]/ const_set k, v else sc.module_eval{ attr_accessor k } send "#{ k }=", v end end break module_eval(e) end end.value end end context = {:A => true, :B => false, :C => true, :D => false, :E => true} be = BoolExp.new "A and ( B or C or D) and E", context p be.value be = BoolExp.new "fork", context p be.value harp:~ > ruby a.rb true a.rb:11:in `initialize': bad exp (RuntimeError) from a.rb:41 regards. -a -- suffering increases your inner strength. also, the wishing for suffering makes the suffering disappear. - h.h. the 14th dali lama