Обработка чисел после \ в обратных ссылках в соответствии со стандартом PCRE

Issue #58 closed
Oleg Sychev repo owner created an issue

Originally reported on Google Code with ID 58 ``` По PCRE The handling of a backslash followed by a digit other than 0 is complicated. Outside a character class, PCRE reads it and any following digits as a decimal number. If the number is less than 10, or if there have been at least that many previous capturing left parentheses in the expression, the entire sequence is taken as a back reference.

Inside a character class, or if the decimal number is greater than 9 and there have not been that many capturing subpatterns, PCRE re-reads up to three octal digits following the backslash, and uses them to generate a data character.

У нас сканер не соблюдает это правило, особенно не учитывает количество предыдущих подмасок - а также восьмеричность кода символа. Также не обрабатывается \g для обратных ссылок.

Валерий, это будет интересовать в первую очередь вас, как поддерживающего работоспособный матчер с обратными ссылками, поэтому задача ваша. Посмотрите к встрече после релиза что неясно в сканере по этому поводу - при встрече обсудим... ```

Reported by `oasychev` on 2011-11-20 21:55:33

Comments (10)

  1. Oleg Sychev reporter

    ``` Еще - здесь или отдельной задачей - надо бы наладить варианты подмасок, упоминаемые на http://www.pcre.org/pcre.txt как DUPLICATE SUBPATTERN NUMBERS и NAMED SUBPATTERNS ```

    Reported by `oasychev` on 2011-12-04 13:04:37

  2. Oleg Sychev reporter

    ``` Полное описание как это должно работать дано выше.

    Остальные части вынесены в отдельные issue.

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

    По работе со сканером/парсером вас может просветить Дмитрий если я буду недоступен. ```

    Reported by `oasychev` on 2011-12-30 15:04:22

  3. Valeriy Streltsov

    ``` Это issue перевожу в fixed, поддержку остальных вариантов реализую в соответствующих issue. ```

    Reported by `vostreltsov` on 2012-01-09 00:00:18

  4. Oleg Sychev reporter

    ``` Боюсь вы слишком легко подошли к этой проблеме:

    1) если число начинается с 0 (\0) оно всегда трактуется как восьмеричный код символа After \0 up to two further octal digits are read. If there are fewer than two digits, just those that are present are used. Thus the sequence \0\x\07 specifies two binary zeros followed by a BEL character (code value 7). Make sure you supply two digits after the initial zero if the pattern character that follows is itself an octal digit.

    2) Код числа считается по восьмеричным цифрам, а не десятичным. \78 будет воспринято не как восьмеричный код 78, а как символ с кодом 7 конкатенированный с символом восьмерки.

    Боюсь что вы этого не учли.

    Также я вижу исправления существующих юнит-тестов лексера, но не вижу новых, а тут много хитрых ситуаций. Нужно добавить на разные варианты (не только упомянутые выше, но и работающие сейчас - разные варианты воспринятия двузначного числа и т.д. ```

    Reported by `oasychev` on 2012-01-09 18:40:58 - Status changed: `InProgress`

  5. Oleg Sychev reporter

    ``` Вот вам на всякий случай таблица примером из руководства по PCRE

    \040 is another way of writing a space \40 is the same, provided there are fewer than 40 previous capturing subpatterns \7 is always a back reference \11 might be a back reference, or another way of writing a tab \011 is always a tab \0113 is a tab followed by the character "3" \113 might be a back reference, otherwise the character with octal code 113 \377 might be a back reference, otherwise the byte consisting entirely of 1 bits \81 is either a back reference, or a binary zero followed by the two characters "8" and "1" ```

    Reported by `oasychev` on 2012-01-09 18:42:31

  6. Valeriy Streltsov

    ``` Доработано.

    3) Если число начинается с 0 - исправлено. Первый символьный класс принял вид [1-9], обработка \0 осуществляется отдельно, т.к. там нет неопределенностей.

    4) Если обратной ссылки с заданным номером нет - возвращается массив: а) читаются все восьмеричные цифры и возвращается символ с этим кодом (символ с кодом 0, если сразу встретилась невосьмеричная цифра); б) далее возвращаются обычные символы как они записаны. Класс regex_handler'а соответствующим образом исправлен.

    5) Сомневаюсь на счет <YYINITIAL>
    0[0-9][0-9]?|[0-9][0-9][0-9] Во-первых, цифры должны быть восьмеричными и после \0 их может не быть вообще (это я исправил). Во-вторых, я не нашел в pcre.txt что можно обозначать символ тремя цифрами подряд. Пока что оставил это, но очень уж сомнительно. На данный момент оно выглядит так: <YYINITIAL>
    0[0-7]?[0-7]?|[0-7][0-7][0-7]

    6) Аналогично исправлено правило для шестнадцатеричного представления символов: с
    x[0-9][0-9] на
    x[0-9a-fA-F]?[0-9a-fA-F]? Также добавлен вариант
    x\{[0-9a-fA-F]*\} ```

    Reported by `vostreltsov` on 2012-01-10 16:17:47

  7. Oleg Sychev reporter

    ``` Когда отвечаете на нумерованные комментарии, ставьте номер на который отвечаете. Как я сейчас: 3) согласен

    4) нужно проапгрейдить еще qtype_preg_parser_test::run_parser - и возможно дописать туда тестик чтобы удостоверится, что парсер все обрабатывает правильно при возврате массива (хотя кросс-тестом вы это проверили)

    5) If more than one rule matches strings from its input, the generated lexer resolves conflicts between rules by greedily choosing the rule that matches the longest string. If more than one rule matches strings of the same length, the lexer will choose the rule that is given first in the JLex specification. Therefore, rules appearing earlier in the specification are given a higher priority by the generated lexer.

    Т.е. второе правильно по альтернативе [0-7][0-7][0-7] никогда не сработает, т.к. оно будет "съедено" ранее расположенным
    [1-9][0-9]?[0-9]? Поэтому альтернативу эту можно смело удалять. Вариант, начинающийся с нуля сработает, т.к. выше расположенному правилу он не соответствует.

    6) согласен

    проследите только чтобы правило на \ с любым символом (не буквенно-цифровым) находилось после других... ```

    Reported by `oasychev` on 2012-01-11 13:30:18

  8. Log in to comment