Определить скобки в BinaryExpression - PullRequest
6 голосов
/ 30 мая 2011

Я строю анализатор выражений, из которого я хотел бы сгенерировать код запроса к базе данных, я довольно далеко продвинулся, но я застрял при точном разборе BinaryExpressions. Их довольно легко разбить на левую и правую, но мне нужно определить круглые скобки и соответственно сгенерировать свой код, и я не вижу, как это сделать.

Пример [пожалуйста, игнорируйте некорректную логику:)]:

a => a.Line2 != "1" && (a.Line2 == "a" || a.Line2 != "b") && !a.Line1.EndsWith("a")

Мне нужно обнаружить 'set' в середине и сохранить их группировку, но я не вижу никакой разницы в выражении по сравнению с обычным BinaryExpression во время синтаксического анализа (я не хотел бы проверять строковое представление для скобок)

Любая помощь будет оценена.

(наверное, стоит упомянуть, что я использую C #)

- Edit-- Я не упомянул, что я использую стандартные классы .Net Expression для построения выражений (пространство имен System.Linq.Expressions)

- Edit2-- Хорошо, я не разбираю текст в коде, я разбираю код в тексте. Так что у моего класса Parser есть такой метод:

void FilterWith<T>(Expression<Func<T, bool>> filterExpression);

, который позволяет вам написать код, подобный этому:

FilterWith<Customer>(c => c.Name =="asd" && c.Surname == "qwe");

, который довольно легко разобрать, используя стандартные классы .Net, моя задача - разобрать это выражение:

FilterWith<Customer>(c => c.Name == "asd" && (c.Surname == "qwe" && c.Status == 1) && !c.Disabled)

Моя задача - сохранить выражения между круглыми скобками в виде единого набора. Классы .Net правильно отделяют части скобок от других, но не указывают, что это набор из-за скобок.

Ответы [ 2 ]

6 голосов
/ 30 мая 2011

Я сам не использовал Expression, но если он работает так же, как и любой другой AST, то эту проблему легче решить, чем вы ее себе представляете. Как заметил другой комментатор, просто поставьте скобки вокруг всех ваших двоичных выражений, и тогда вам не придется беспокоиться о порядке операций.

Кроме того, вы можете проверить, имеет ли генерируемое вами выражение более низкий приоритет, чем содержащее выражение, и, если это так, поставить вокруг него круглые скобки. Поэтому, если у вас есть дерево, подобное этому [* 4 [+ 5 6]] (где узлы дерева представлены рекурсивно как [node left-subtree right-subtree]), вы будете знать при записи дерева [+ 4 5], что оно содержится внутри операции *, которая имеет более высокий приоритет чем операция + и, следовательно, требует, чтобы любое из его непосредственных поддеревьев было помещено в скобки. Псевдокод может выглядеть примерно так:

function parseBinary(node) {
    if(node.left.operator.precedence < node.operator.precedence)
        write "(" + parseBinary(node.left) + ")"
    else
        write parseBinary(node.left)
    write node.operator
    // and now do the same thing for node.right as you did for node.left above    
}

Вам понадобится таблица приоритетов для различных операторов и способ найти самого оператора, чтобы выяснить, что это такое, и, следовательно, каков его приоритет. Тем не менее, я думаю, что вы можете понять эту часть.

0 голосов
/ 30 мая 2011

При построении анализатора выражений сначала необходим анализатор, а для этого нужен токенизатор.

Токенизатор - это фрагмент кода, который читает выражение, генерирует токены (которые могут быть действительными или недействительными).), для определенного синтаксиса.

Таким образом, ваш синтаксический анализатор, используя токенизатор, читает выражение в установленном порядке (слева направо, справа налево, сверху вниз, что бы вы ни выбрали)и создает дерево, которое отображает выражение.

Затем анализатор интерпретирует дерево в выражение, придавая ему окончательный смысл.

...