Pegjs: Добавить возможность отслеживать положение узла

Созданный на 13 авг. 2011  ·  15Комментарии  ·  Источник: pegjs/pegjs

Парсеры, созданные PEG.js, в настоящее время не отслеживают позицию (строку и столбец). Я хотел бы добавить эту функцию, поскольку она была бы весьма полезной.

Один из способов — добавить свойства line и column к каждому объекту, возвращаемому в результате совпадения:

start = "a" b:"b" { return [b.line, b.column]; } // Returns [1, 2] on the input "ab".

Другой способ — просто сделать специальные переменные line и column доступными внутри действий/предикатов, ссылаясь на позицию начала текущего правила:

start = "a" "b" { return [line, column]; } // Returns [1, 1] on the input "ab".

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

Оба способа повредят производительности. Чтобы предотвратить это в случаях, когда отслеживание позиции не требуется, отслеживание должно быть включено только в том случае, если опция trackPosition с истинным значением передается в PEG.buildParser при генерации парсера.

Самый полезный комментарий

@tomitrescak эта функция, по-видимому, менялась несколько раз в прошлом. Посмотрите журнал изменений для получения дополнительной информации. tl;dr заключается в том, что вам нужно использовать функцию location() в вашей грамматике

Все 15 Комментарий

Любой вариант будет отличным. Для моих нужд просто строка, столбец будет в порядке.

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

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

Мне тоже больше нравится первый подход.

Одним из возможных способов повышения эффективности является использование функции name.position, чтобы ее можно было вычислять лениво. Затем это может вернуть массив из двух элементов строки и столбца. Просто идея для тех, кто не хочет рассчитывать позицию для каждого отдельного элемента.

Оглядываясь назад, кажется, что лучше указать начальную и конечную позиции символов, а затем предоставить вспомогательную функцию в библиотеке, которая преобразует позицию в строку/столбец. Так как в общем случае вам не нужна строка/столбец, если нет ошибки, и как только вы достигли ошибки, вам обычно это нужно только один раз.

В настоящее время я делаю это хакерским способом, злоупотребляя переменными startPos0 и pos , что кажется хакерским, но пока работает.

Пока не будет официального исправления, я включаю эту функцию (грубая копия computeErrorPosition ) в начало своих грамматик. По крайней мере, это даст мне _текущую_ позицию (хотя и не позицию отдельных узлов):

  function computeCurrentPos() {
    /*
     * The first idea was to use |String.split| to break the input up to the
     * error position along newlines and derive the line and column from
     * there. However IE's |split| implementation is so broken that it was
     * enough to prevent it.
     */

    var line = 1;
    var column = 1;
    var seenCR = false;

    for (var i = 0; i < pos; i++) {
      var ch = input.charAt(i);
      if (ch === '\n') {
        if (!seenCR) { line++; }
        column = 1;
        seenCR = false;
      } else if (ch === '\r' | ch === '\u2028' || ch === '\u2029') {
        line++;
        column = 1;
        seenCR = true;
      } else {
        column++;
        seenCR = false;
      }
    }

    return { line: line, column: column, pos: pos };
  }

Эта проблема была исправлена серией коммитов .

Теперь вы можете передать параметр trackLineAndColumn функции PEG.buildParser :

var parser = PEG.buildParser(myGrammar, { trackLineAndColumn: true});

Установка для trackLineAndColumn значения true делает две новые переменные видимыми в действиях и предикатах — line и column . Для действий эти переменные обозначают начальную позицию выражения действия, а в предикатах они обозначают текущую позицию. Несколько иное поведение мотивировано ожидаемым использованием.

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

В описании проблемы я упомянул другой подход к этой проблеме: добавление свойств line и column к каждому результату совпадения. Хотя это решение было чище и предпочитаемо пользователями, я понял, что нельзя установить свойства для примитивных значений, таких как строки, числа или логические значения (которые часто возвращаются как результаты сопоставления). Возврат экземпляров объектов-оберток (например, String , Number или Boolean ) был бы возможным обходным решением, но это, вероятно, привело бы к тонким ошибкам в парсерах, созданных пользователями, потому что эти оболочки ведут себя немного иначе, чем примитивы. Таким образом, я решил реализовать альтернативное предложение.

Будет ли обновлена ​​тестовая онлайн-страница для поддержки этой функции?

@paulftw Онлайн-редактор всегда использует последнюю стабильную версию PEG.js (в настоящее время 0.6.2). Я обновлю его, как только выпущу PEG.js 0.7.0 (который будет включать эту функцию). Если не случится чего-то неожиданного, это произойдет во второй половине апреля.

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

Только что понял, что все строки и столбцы основаны на 1, в то время как массивы JS, а также почти все современные языки и библиотеки используют индексирование на основе 0.

Есть ли шанс отменить это дизайнерское решение?

@paulftw Можете ли вы привести пример генератора синтаксического анализатора, который сообщает строки и столбцы как отсчитываемые от 0?

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

Есть ли шанс отменить это дизайнерское решение?

Да, если меня убедят :-)

Я использую peg.js для выделения текста в редакторе Ace. Вполне естественно, что номера линий Ace начинаются с 0.
Однако кажется, что в Bison локации основаны на 1.
http://git.savannah.gnu.org/cgit/bison.git/tree/src/location.c#n73

Если это действительно так, то я должен прекратить спорить.

Не уверен, какой пример вы хотите увидеть.
Сейчас я использую следующий код, чтобы найти имя символа:

похититель
= "" { вернуть новую позицию (строка - 1, столбец - 1); }

символ
= начало: имя захватчика:ИДЕНТ. конец:захватчик S* { вернуть новый символ(имя, новый диапазон(начало, конец)); }

@paulftw Я выделил эту проблему в отдельный вопрос . Я бы подождал, пока пользователи примут 0.7.0, и посмотрю, какое преобладающее использование решит.

Я знаю, что это давно закрыто, но как я могу заставить это работать? совсем нуб в этом. Я скомпилировал свою грамматику с флагом "trackLineAndColumn': true", но узлы по-прежнему не содержат строк и столбцов. Что еще нужно?

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

Установка для trackLineAndColumn значения true делает две новые переменные видимыми в действиях и предикатах — строку и столбец. Для действий эти переменные обозначают начальную позицию выражения действия, а в предикатах они обозначают текущую позицию. Несколько иное поведение мотивировано ожидаемым использованием.

@tomitrescak эта функция, по-видимому, менялась несколько раз в прошлом. Посмотрите журнал изменений для получения дополнительной информации. tl;dr заключается в том, что вам нужно использовать функцию location() в вашей грамматике

Была ли эта страница полезной?
0 / 5 - 0 рейтинги