Я реализую DSL, который имеет синтаксис:Treetop булево логические операции
"[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
Обновления
Parser класс
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
My Treetop ржавый, но как насчет чего-то вроде выражения правила; выражение операнда слова/выражения; end'? Или выражается через повторение вместо рекурсии: выражение правила; ключевое слово (ключевое слово операнда) *; конец' –
@ JörgWMittag не работает. Treetop ожидает места в позиции 'operator' в обоих примерах – djsmentya
Вы не определяете, ожидаете ли вы, что И или ИЛИ имеют больший приоритет. Общепринятое использование на компьютерных языках имеет И имеет более высокий приоритет, чем OR, но вам нужно решить, так или иначе, или ваша грамматика всегда будет иметь круглые скобки. Если вы ответите на это, я могу предложить ответ на ваш вопрос. – cliffordheath