[英]Treetop boolean logic operations
I am implementing DSL which has syntax: 我正在实现具有语法的DSL:
"[keyword] or ([other keyword] and not [one more keyword])"
Each keyword will transform to boolean ( true
, false
) value and after that it should be calculated using operators and, or, not
每个关键字都将转换为布尔值(
true
, false
),之后应使用运算符and, or, not
My current grammar rules match only strings [keyword] or [other keyword]
and fails on stings [keyword] or [other keyword] or [one more keyword]
我当前的语法规则只匹配字符串
[keyword] or [other keyword]
并且在stings [keyword] or [other keyword] or [one more keyword]
上失败
How to write grammar that match any ammount of or
, and
constructions? 如何写匹配任何ammount的是语法
or
, and
结构?
Grammar: 语法:
grammar Sexp
rule expression
keyword operand keyword <ExpressionLiteral>
end
rule operand
or / and <OperandLiteral>
end
rule or
'or' <OrLiteral>
end
rule and
'and' <AndLiteral>
end
rule keyword
space '[' ( '\[' / !']' . )* ']' space <KeywordLiteral>
end
rule space
' '*
end
end
Updates 更新
Parser class 解析器类
class Parser
require 'treetop'
base_path = File.expand_path(File.dirname(__FILE__))
require File.join(base_path, 'node_extensions.rb')
Treetop.load(File.join(base_path, 'sexp_parser.treetop'))
def self.parse(data)
if data.respond_to? :read
data = data.read
end
parser =SexpParser.new
ast = parser.parse data
if ast
#self.clean_tree(ast)
return ast
else
parser.failure_reason =~ /^(Expected .+) after/m
puts "#{$1.gsub("\n", '$NEWLINE')}:"
puts data.lines.to_a[parser.failure_line - 1]
puts "#{'~' * (parser.failure_column - 1)}^"
end
end
private
def self.clean_tree(root_node)
return if(root_node.elements.nil?)
root_node.elements.delete_if{|node| node.class.name == "Treetop::Runtime::SyntaxNode" }
root_node.elements.each {|node| self.clean_tree(node) }
end
end
tree = Parser.parse('[keyword] or [other keyword] or [this]')
p tree
p tree.to_array
node extension 节点扩展
module Sexp
class KeywordLiteral < Treetop::Runtime::SyntaxNode
def to_array
self.text_value.gsub(/[\s\[\]]+/, '')
end
end
class OrLiteral < Treetop::Runtime::SyntaxNode
def to_array
self.text_value
end
end
class AndLiteral < Treetop::Runtime::SyntaxNode
def to_array
self.text_value
end
end
class OperandLiteral < Treetop::Runtime::SyntaxNode
def to_array
self.elements.map{|e| e.to_array}
end
end
class ExpressionLiteral < Treetop::Runtime::SyntaxNode
def to_array
self.elements.map{|e| e.to_array}.join(' ')
end
end
end
Ok, thanks for that clarification. 好的,谢谢你的澄清。 In Ruby, "false and true or true" is true, because the "and" is evaluated first (it has higher precedence).
在Ruby中,“false和true或true”是正确的,因为首先评估“and”(它具有更高的优先级)。 To parse this, you need one rule for the "or" list (the disjunctions) which calls another rule for the "and" list (the conjunctions).
要解析这个,你需要一个规则用于“或”列表(析取),它为“和”列表(连词)调用另一个规则。 Like this:
像这样:
rule expression
s disjunction s
{ def value; disjunction.value; end }
end
rule disjunction
conjunction tail:(or s conjunction s)*
{ def value
tail.elements.inject(conjunction.value) do |r, e|
r or e.conjunction.value
end
end
}
end
rule conjunction
primitive tail:(and s primitive s)*
{ def value
tail.elements.inject(primitive.value) do |r, e|
r and e.primitive.value
end
end
}
end
rule primitive
'(' expression ')' s { def value; expression.value; end }
/
not expression s { def value; not expression.value; end }
/
symbol s { def value; symbol.value; end }
end
rule or
'or' !symbolchar s
end
rule and
'and' !symbolchar s
end
rule not
'not' !symbolchar s
end
rule symbol
text:([[:alpha:]_] symbolchar*) s
{ def value
lookup_value(text.text_value)
end
}
end
rule symbolchar
[[:alnum:]_]
end
rule s # Optional space
S?
end
rule S # Mandatory space
[ \t\n\r]*
end
Note some things: 注意一些事情:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.