Pegjs: Как сохранить разделители пробелов?

Созданный на 3 окт. 2019  ·  6Комментарии  ·  Источник: pegjs/pegjs

Тип проблемы

  • Отчет об ошибке: _no_
  • Запрос функции: _no_
  • Вопрос: _да_
  • Не проблема: _no_

Предпосылки

  • Вы можете воспроизвести проблему?: _yes_
  • Вы искали проблемы с репозиторием?: _yes_
  • Вы смотрели форумы?: _yes_
  • Вы выполняли поиск в Интернете (google, yahoo и т. д.)?: _yes_

Я изо всех сил пытаюсь заставить парсер PEG.js сохранять исходные пробелы уравнения.

Текущее поведение: 2 * 5 + SUM(1, 2, 3)

[
   "2",
   "*",
   "5",
   "+",
   "SUM",
   "(",
   [
      "1",
      ",",
      "2",
      ",",
      "3"
   ],
   ")"
]

Желаемое поведение : 2 * 5 + SUM(1, 2, 3)

[
   "2",
   " ",
   "*",
   " ",
   "5",
   " ",
   "+",
   " ",
   "SUM",
   "(",
   [
      "1",
      ",",
      " ",
      "2",
      ",",
      " ",
      "3"
   ],
   ")"
]

Грамматика для копирования: https://pastebin.com/zpwqT6Uw
Площадка PEG.js https://pegjs.org/online

Что мне не хватает?

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

@marek-baranowski Еще один нежный пинг :smiley_cat:

Кроме того, я написал плагин pegjs-syntactic-actions для PEG.js, чтобы облегчить отладку грамматик и, в частности, посмотреть, какие символы захватываются каким правилом независимо от действий, что, вероятно, является вашей проблемой здесь, как объяснил @StoneCypher.

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

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

@futagoza невероятно жаль вас беспокоить, но я впервые имею дело с PEG.js, и эта проблема для меня критична. Могу я попросить вас о небольшой подсказке?

С уважением,
Марек

Я пытался просмотреть вашу грамматику (вчера и только что), но, поскольку ее действительно сложно понять (не говоря уже о соглашениях об именах, формат, если честно, повсюду), мне потребовалось некоторое время, чтобы найти решение:

  1. Правила, которые потребляют пространство и возвращают данные (например, const возвращает [left_space, cnst, right_space] )
  2. Любое правило/действие, которое принимает результат, должно делать что-то вроде этого: [].concat.apply([], con)

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

Если нет, если вы готовы потратить время и привести в порядок грамматику и переименовать некоторые правила (чтобы было легче понять, что вы хотите), то я с удовольствием попробую еще раз 😉

@marek-baranowski - Извините, я не видел этого до сих пор. Надеюсь, это все еще полезно для вас

Если вы хотите сохранить пробелы, просто относитесь к ним как к сопоставляемому содержимому.

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

Кроме того... зачем вам такие случайные символы, кроме вызова функции? Парсер должен суммировать их для вас.

В любом случае

Это то, что вы просили:

Document = Expression*

Whitespace
  = tx:[ \r\n]+ { return tx.join(''); }

Number
  = str:[0-9]+ { return str.join(''); }

Oper
  = '+'
  / '-'
  / '/'
  / '*'
  / ','

Label
  = l:[a-zA-Z]+ { return l.join(''); }

Parens 
  = '(' Whitespace? ex:Expression* Whitespace? ')' { return ex; }

Expression 
  = Number 
  / Oper
  / Whitespace
  / Label
  / Parens
  / [^()]+

image

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

Document = Expression*

Whitespace
  = tx:[ \r\n]+ { return { 
    ast: 'whitespace', value: tx.join('') 
  }; }

Number
  = str:[0-9]+ { return {
    ast: 'number', value: parseInt(str,10)
  }; }

Oper
  = '+' { return { ast: 'oper', value: 'add' }}
  / '-' { return { ast: 'oper', value: 'subtract' }}
  / '/' { return { ast: 'oper', value: 'divide' }}
  / '*' { return { ast: 'oper', value: 'multiply' }}
  / ',' { return { ast: 'oper', value: 'sequence' }}

Label
  = l:[a-zA-Z]+ { return { 
    ast: 'label', value: l.join('') 
  }; }

Parens 
  = '(' Whitespace? ex:Expression* Whitespace? ')' { 
    return { ast: 'parens', value: ex 
  }; }

Expression 
  = Number 
  / Oper
  / Whitespace
  / Label
  / Parens
  / [^()]+

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

image

@marek-baranowski - я бы хотел немного уменьшить размер этого трекера

Если это то, что вам нужно, не могли бы вы закрыть этот вопрос? Спасибо 😄

Если это не так, дайте мне знать, почему, и я попробую еще раз

@marek-baranowski Еще один нежный пинг :smiley_cat:

Кроме того, я написал плагин pegjs-syntactic-actions для PEG.js, чтобы облегчить отладку грамматик и, в частности, посмотреть, какие символы захватываются каким правилом независимо от действий, что, вероятно, является вашей проблемой здесь, как объяснил @StoneCypher.

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

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

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

Смежные вопросы

StoneCypher picture StoneCypher  ·  8Комментарии

brettz9 picture brettz9  ·  8Комментарии

futagoza picture futagoza  ·  13Комментарии

dmajda picture dmajda  ·  15Комментарии

dmajda picture dmajda  ·  7Комментарии