Предотвратите чрезмерное замедление работы PEG.jsJavascript

Форум по Javascript
Ответить Пред. темаСлед. тема
Anonymous
 Предотвратите чрезмерное замедление работы PEG.js

Сообщение Anonymous »

Большая часть примеров PEG.js (или Peggy) не поддерживают ничего, кроме базовой математической формулы. Я написал эту арифметическую логику, чтобы обеспечить полную поддержку математического анализа с основой для добавления пользовательских функций.
Конечно, в рабочей среде операторы console.log() не будут работать быть там, но он используется для определения того, сколько раз выполняются функции оценки.
Похоже, что с каждым уровнем в порядке операций количество выполнений кода удваивается. .
Мои вопросы есть... как можно избежать этой проблемы с производительностью?
Я новичок в PEG, и, возможно, существует расширенная функция, которая предотвратит такую ​​сложную атаку.
Приведенный ниже код можно поместить в https://peggyjs.org/online.html
А вот несколько примеров функций, на которые стоит обратить внимание:
5*(3+3)
Эта 7-символьная функция создает более 500 операторов console.log
Возможно, это хороший первый признак того, что синтаксический анализ неоптимален. Я не понимаю, как можно использовать процесс из 500 шагов для анализа 7 символов.
Это достаточно грубо, что PEG.js нашел 500 задач, но настоящая проблема в том, что он выполняется. часть обратного вызова (часть {}, содержащая console.log) каждый раз. Каждый раз. Обратите внимание, что это тот же языковой элемент, ему передается «9», а в прошлый раз он вернул 9. Есть ли какой-нибудь трюк, чтобы PEG.js мог просто запомнить это? Текущий код тривиален, но более сложные функции выполняют значительный код, и разработчик не ожидает, что он будет выполнен 64 раза, если грамматика присутствует в формуле только один раз.
1.1 / ( 2 * ( (9 * 9) + (9 * 9) + (9 * 9) ) ) или
1.1 / (( 2 * ( 9 * 9 + 9 * 9 + 9 * 9 ) ) )
Любой из этих вариантов работает нормально (можно оставить консоль браузера закрытой, количество журналов дикое), но учтите, что они анализируют быстро.
1.1 / (( 2 * ( (9 * 9) + (9 * 9) + (9 * 9) ) ) )
Здесь появляется скала. Всего лишь еще один уровень сложности, чем два вышеперечисленных, но он полностью заблокирует браузер на достаточное время.
{
const operations = {
"√": (power, value) => Math.pow(value, 1 / power),
"^": (base, exponent) => base ** exponent,
"*": (multiplicand, multiplier) => multiplicand * multiplier,
"/": (dividend, divisor) => dividend / divisor,
"+": (addend1, addend2) => addend1 + addend2,
"-": (minuend, subtrahend) => minuend||0 - subtrahend,
"": (a, b) => a > b,
"=": (a, b) => a >= b,
"=": (a, b) => a == b,
"!=": (a, b) => a != b
};
}

// Define our end result should be something ReadyToReturn
Start = _ value:ReadyToReturn _ { return value; }

// * means zero or more so even empty strings count as whitespace
_ "whitespace" = [ \t\n\r]*

NumericValue
= scientific:(_ "-"? [0-9]+ ("." [0-9]+)? [eE] [+-]? [0-9]+) { console.log('scientific'); return text(); }
/ double:(_ $("-"? [0-9]+ "." [0-9]* / "-"? "." [0-9]+)) { console.log('double'); return Number(text()); }
/ integer:(_ "-"? [0-9]+) { console.log('integer'); return parseInt(text(), 10); }

QuoteText = "\"" chars:([^\\"] / "\\" .)* "\"" { return chars.join(""); }

PlainText = [a-zA-Z0-9 ]+ { return text().trim(); }

SimpleValue = NumericValue / QuoteText / PlainText

// After functions and columns are handled, we are left with simple numbers and ready to do math
ReadyToCalculate
= negate:[-]? result:Function {
if (!negate) {
return result;
}
return isNumber(result) ? 0 - result : "-" + result;
}
/ SimpleValue

// Functions need to be processed in the order they appear in the formula so finding arguments works correctly
Function = firstFunction:(
Parentheses
/ RoundDown
/ RoundUp
) {
return firstFunction;
}

Parentheses = "(" _ expr:ReadyToReturn _ ")" {
console.log('( )');
return expr;
}

RoundDown = "ROUNDDOWN(" _ value:ReadyToReturn places:(_ "," _ ReadyToReturn)? _ ")" {
console.log('ROUNDDOWN');
const digitNum = (places && places[2]) || 0;
const base = 10 ** digitNum
if (value < 0) {
return Math.ceil(value * base) / base;
}
return Math.floor(value * base) / base;
}

RoundUp = "ROUNDUP(" _ value:ReadyToReturn _ places:("," _ ReadyToReturn _)? ")" {
console.log('ROUNDUP');
const digitNum = (places && places[2]) || 0;
const base = 10 ** digitNum
if (value < 0) {
return Math.floor(value * base) / base;
}
return Math.ceil(value * base) / base;
}

////////////////////////////////////////////////////////
// This is the order of operations part.
// Each ReadyTo* definition expects the previous ReadyTo* which means that higher level has completed.
////////////////////////////////////////////////////////

// When handling roots, the two definitions are processed in order.
// If it can consume a number to the left, it will
// Then it will process √ characters without needing a number to the left
// Finally, if no root work needs to be done, a ReadyToCalculate can simploy pass through
ReadyToExponent
= head:ReadyToCalculate _ tail:(_ "√" _ ReadyToCalculate)+ {
console.log('_√_');
return tail.reduce((result, element) => operations[element[1]](result, element[3]), head);
}
/ negate:[-]? tail:(_ "√" _ ReadyToCalculate)+ {
console.log('√_');
if (negate) {
return 0 - tail.reduce((result, element) => operations[element[1]](result, element[3]), 2);
}
return tail.reduce((result, element) => operations[element[1]](result, element[3]), 2);
}
/ ReadyToCalculate

ReadyToMultiply
= head:ReadyToExponent tail:(_ "^" _ ReadyToExponent)+ {
console.log('Exponent');
return tail.reduce((result, element) => operations[element[1]](result, element[3]), head);
}
/ ReadyToExponent

ReadyToAdd
= head:ReadyToMultiply tail:(_ ("*" / "/") _ ReadyToMultiply)+ {
console.log('Multiply');
return tail.reduce((result, element) => operations[element[1]](result, element[3]), head);
}
/ ReadyToMultiply

ReadyToCompare
= head:ReadyToAdd tail:(_ ("+" / "-") _ ReadyToAdd)+ {
console.log('Add');
return tail.reduce((result, element) => operations[element[1]](result, element[3]), head);
}
/ ReadyToAdd

ReadyToReturn
= head:ReadyToCompare tail:(_ ("" / "!=" / "=") _ ReadyToCompare)+ {
console.log('Compare');
return tail.reduce((result, element) => operations[element[1]](result, element[3]), head);
}
/ ReadyToCompare


Подробнее здесь: https://stackoverflow.com/questions/793 ... -on-peg-js
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

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

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение
  • Как добавить неявное умножение в базовую грамматику калькулятора PHP PEG?
    Anonymous » » в форуме Php
    0 Ответы
    21 Просмотры
    Последнее сообщение Anonymous
  • Правильный порядок математических выражений в грамматике PEG
    Anonymous » » в форуме Php
    0 Ответы
    32 Просмотры
    Последнее сообщение Anonymous
  • Переверните ассоциативный массив и предотвратите потерю новых значений из-за новых коллизий ключей
    Anonymous » » в форуме Php
    0 Ответы
    14 Просмотры
    Последнее сообщение Anonymous
  • IOS Safari: предотвратите нажатие мягкой клавиатуры, используя прокси -вход
    Anonymous » » в форуме IOS
    0 Ответы
    9 Просмотры
    Последнее сообщение Anonymous
  • IOS Safari: предотвратите нажатие мягкой клавиатуры, используя прокси -вход
    Anonymous » » в форуме IOS
    0 Ответы
    1 Просмотры
    Последнее сообщение Anonymous

Вернуться в «Javascript»