Древовидная логическая логика операций

Я реализую DSL, который имеет синтаксис:

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

Каждое ключевое слово будет преобразовано в логическое (true, false) значение и после этого оно должно быть рассчитано с использованием операторов and, or, not

Мои текущие правила грамматики соответствуют только строкам [keyword] or [other keyword] и терпит неудачу в укусах [keyword] or [other keyword] or [one more keyword]

Как написать грамматику, соответствующую любому количеству or, 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

1 ответ

Хорошо, спасибо за это разъяснение. В 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

Обратите внимание на некоторые вещи:

  • за ключевыми словами не должно следовать сразу символ символа. Я использую негативную перспективу для этого.
  • Верхнее правило потребляет начальные пробелы, затем почти каждое правило использует следующие пробелы (это моя политика). Вы должны проверить свою грамматику с минимальным и максимальным пробелом.
  • Нет необходимости использовать класс синтаксического узла в каждом правиле, как вы это сделали.
  • Вы можете увидеть, как продолжить шаблон для сложения, умножения и т. Д.
  • Я дал набросок некоторого кода, который оценивает выражение. Используйте что-нибудь красивее, пожалуйста!
Другие вопросы по тегам