2015-09-03 67 views
3

我实现DSL其中有语法:树顶布尔逻辑运算

"[keyword] or ([other keyword] and not [one more keyword])" 

每个关键字将转变为布尔(truefalse)值之后,它应该使用运营商and, or, not

我目前的计算语法规则仅匹配字符串[keyword] or [other keyword]并且在刺激时失败[keyword] or [other keyword] or [one more keyword]

如何编写与匹配的任何ammount的语法,and建筑?

语法:

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 

更新

分析器类

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 

节点延伸

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 
+0

我的树梢是生锈的,但是如何处理像规则表达;关键字/表达式操作数表达式; end'?或者通过重复而不是递归表达:'rule expression;关键字(操作数关键字)*;结束' –

+0

@JörgWMittag不起作用。 Treetop期望在两个示例中的'operator'的位置空间 – djsmentya

+1

您没有定义您是否期望AND和OR具有更高的优先级。这是计算机语言中的常见用法,AND具有比OR更高的优先级,但您需要确定一种方式或另一种方式,或者您的语法总是需要括号。如果你回答这个问题,我可以回答你的问题。 – cliffordheath

回答

4

好的,谢谢你的澄清。在Ruby中,“假和真或真”是真实的,因为“和”首先被评估(它具有更高的优先级)。为了解析这个,你需要一个“或”列表(不连续)的规则,它为“和”列表(连词)调用另一个规则。就像这样:

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 

注意一些事情:

  • 关键字一定不能紧跟一个符号字符。我为此使用了负面看法。
  • 最上面的规则消耗前导空白,然后几乎每个规则消耗下面的空白(这是我的策略)。你应该用最小和最大空白来测试你的语法。
  • 没有必要在每条规则上使用syntaxnode类,就像你所做的那样。
  • 你可以看到如何继续添加,乘法等模式
  • 我已经给出了一些评估表达式的代码的草图。请用更漂亮的东西!
+0

“假或真和真”是真 –

+1

Gah!完全正确。我会编辑我的描述。代码仍然正确。 – cliffordheath