Re[5]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 17.11.21 11:38
Оценка: 3 (1) +1 :))) :))
Здравствуйте, Shmj, Вы писали:

НС>>Т.е. просто одно несложное выражение?

S>Типа того.

Тогда проще всего ознакомиться с алгоритмом Пратта и накидать нужный движочек за пару часов с нуля. Если время работы важнее времени старта — накинь еще пару часиков на реализацию простенького компилятора. В любом случае, за рабочий день, максимум два справишься.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[21]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 23.11.21 06:31
Оценка: 39 (4) +2
Здравствуйте, vaa, Вы писали:

vaa>Да, чем может System.Console навредить системе? Про возможности рефлексии знаю.

vaa>попробуйте получить список файлов например из каталога C:\Windows
Ок, вижу, что рассуждения по индукции — не ваша сильная сторона.
https://dotnetfiddle.net/Z86GOC
(каталога C:\Windows в убунту нету).
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[6]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 18.11.21 08:20
Оценка: +4 -1
Здравствуйте, vaa, Вы писали:

vaa>Почему нет?


Потому что тащить большой и тяжелый движок ради копеечной функциональности — с технической точки зрения безумие. Это как мешок картошки с дачи везти карьерным самосвалом на 200т.

vaa>если там написано: "$A + $B" где А и B некоторые переменные, то почему не использовать стандартный C# $"{A}{B}"?


Потому что правило может задаваться порльзователем, а не программистом.

vaa>если a и b поля таблицы то это вообще решается на уровне SQL.


И привет SQL injection?
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[11]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 18.11.21 09:10
Оценка: +5
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Затаскивание полноценного языка ради вычисления формулы — это не решение задачи бизнеса, это банальнейшая халтура. Использование Питона в данном конкретном случае не имеет ни одного преимущества, и при этом привносит в проект огромное количество недостатков.
А то. "У меня была проблема, и я придумал решить её, втащив в программу Питон. Теперь у меня две проблемы".
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[5]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 19.11.21 07:53
Оценка: -4
Здравствуйте, Shmj, Вы писали:

S>Вот только вопрос безопасности все-таки приходится рассмотреть. Можно ли как-то ограничить, чтобы никакого зла нельзя было сделать через этот скрипт?

Насколько помню это для внутренних нужд. Если у вас сотрудникам не доверяют о чем вообще может идти речь?
Можно предложить аудит кода, пусть начальник СБ электронной подписью заверяет код. если подписи не валидная не выполнять код.
Как тебе такое? А?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[19]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 29.11.21 10:56
Оценка: 144 (3)
Здравствуйте, Sinclair, Вы писали:

S>Не знаю, будет ли парсер, основанный на Пратте, более простым.


На счет простоты есть сомнения. Я взял готовый парсер, доработал выбрасывая лишнее и потратил треть от времени на recursive descent, который делал честно с нуля.
Т.е. мне не пришлось тратить время на вещи вида "а как реализовать это правило", "а как надо парсить вот такое", "нужен префикс или инфикс" и тд — собтсвенно самое сложное я взял готовым. Сам алгоритм Пратта на этом фоне можно даже никак не учитывать.
При этом кода вышло чуть больше, чем в recursive descent.
Подозреваю, если вдруг решу сделать такое полностью с нуля, времени уйдет намного больше. В бнф грамматике всё дадено, что и как парсить, а тут такого нет

  Парсер по методу Пратта
Парсер:
function make_parse() {
    let symbol_table = {};
    let currentToken;
    let tokens;
    let token_nr;

    let itself = function () {
        return this;
    };

    let advance = function (id) {
        let type, o, token, value;
        if (id && currentToken.id !== id) {
            currentToken.error(`Expected ${id}`);
        }
        if (token_nr >= tokens.length) {
            currentToken = symbol_table['(end)'];
            return;
        }
        token = tokens[token_nr];
        token_nr += 1;
        value = token.value;
        type = token.type;
        if (type === 'name') {
            o = symbol_table['(name)'];
            type = 'variable';
        } else if (type === 'operator' || type === 'group') {
            o = symbol_table[value];
            if (!o) {
                token.error('Unknown operator.');
            }
        } else if (type ===  'number') {
            o = symbol_table['(literal)'];
            type = 'literal';
        } else {
            token.error('Unexpected token.');
        }
        currentToken = Object.create(o);
        currentToken.type = type;
        // currentToken.line_nr  = token.line_nr;
        // currentToken.column_nr = token.column_nr;
        currentToken.value = value;
        return currentToken;
    };

    let expression = function (rbp) {
        let left;
        let t = currentToken;
        advance();
        left = t.nud();
        while (rbp < currentToken.lbp) {
            t = currentToken;
            advance();
            left = t.led(left);
        }
        return left;
    };

    let original_symbol = {
        nud: function () {
            this.error('Undefined.');
        },
        led: function (left) {
            this.error('Missing operator.');
        }
    };

    let symbol = function (id, bp) {
        let s = symbol_table[id];
        bp = bp || 0;
        if (s) {
            if (bp >= s.lbp) {
                s.lbp = bp;
            }
        } else {
            s = Object.create(original_symbol);
            s.id = s.value = id;
            s.lbp = bp;
            symbol_table[id] = s;
        }
        return s;
    };

    let infix = function (id, bp, led) {
        let s = symbol(id, bp);
        s.led = led || function (left) {
            this.first = left;
            this.second = expression(bp);
            this.type = 'binary';
            return this;
        };
        return s;
    };

    let prefix = function (id, nud) {
        let s = symbol(id);
        s.nud = nud || function () {
            this.first = expression(70);
            this.type = 'unary';
            return this;
        };
        return s;
    };

    symbol('(end)');
    symbol('(name)').nud = itself;
    symbol(')');
    symbol('(literal)').nud = itself;

    infix('+', 50);
    infix('-', 50);

    infix('*', 60);
    infix('/', 60);
    infix('%', 60);

    infix('^', 70);

    prefix('-');
    prefix('(', function () {
        let e = expression(0);
        advance(')');
        return e;
    });

    return function (array_of_tokens) {
        tokens = array_of_tokens;
        token_nr = 0;
        advance();
        let e = expression(0);
        advance('(end)');

        return e;
    };
}

module.exports = {make_parse};

Токенизатор:
const rx_crlf = /\n|\r\n?/;

function tokenize(source) {
    const lines = (Array.isArray(source))
        ? source
        : source.split(rx_crlf);
    const result = [];

    lines.forEach(function (line, line_nr) {
        const rx_token = /(\u0020+)|([a-zA-Z][a-zA-Z_0-9]*)|(\d+(?:\.\d+)?(?:[eE][+\-]?\d+)?)|(\(|\))|([\+\-\/*\%\^])/y;

// Capture Group
// [1]  Whitespace
// [2]  Name
// [3]  Number
// [4]  Punctuator

        let column_nr = 0;
        let make = function (type, value) {

// Make a token object and append it to the result.

            result.push({
                type,
                value,
                line_nr,
                column_nr
            });
        };

        while (column_nr < line.length) {
            let captives = rx_token.exec(line);
            if (!captives) {
                throw new SyntaxError(
                    "line "
                    + line_nr
                    + " column "
                    + column_nr
                );
            } else if (captives[1]) {
                // ignore
            } else if (captives[2]) {
                make("name", captives[2]);
            } else if (captives[3]) {
                make("number", captives[3]);
            } else if (captives[4]) {
                make("group", captives[4]);
            } else if (captives[5]) {
                make("operator", captives[5]);
            }
            column_nr = rx_token.lastIndex;
        }
    });
    return result;
}

module.exports = {tokenize};

const {tokenize} = require('./tokenize');
const {make_parse} = require('./pratt');
const parse = make_parse();

const tokens = tokenize('2 * (-2.9*k - 8)');
const x = parse(tokens);

console.log(JSON.stringify(x, null, 2));


Вот хороший пример — по фрагменту кода догадаться, что же именно оно парсит

infix("(", 80, function (left) {
        let a = [];
        if (left.id === "." || left.id === "[") {
            this.arity = "ternary";
            this.first = left.first;
            this.second = left.second;
            this.third = a;
        } else {
            this.arity = "binary";
            this.first = left;
            this.second = a;
            if ((left.arity !== "unary" || left.id !== "function") &&
                    left.arity !== "name" && left.id !== "(" &&
                    left.id !== "&&" && left.id !== "||" && left.id !== "?") {
                left.error("Expected a variable name.");
            }
        }
        if (token.id !== ")") {
            while (true) {
                a.push(expression(0));
                if (token.id !== ",") {
                    break;
                }
                advance(",");
            }
        }
        advance(")");
        return this;
    });
Отредактировано 29.11.2021 13:50 Pauel . Предыдущая версия . Еще …
Отредактировано 29.11.2021 11:02 Pauel . Предыдущая версия .
Отредактировано 29.11.2021 11:01 Pauel . Предыдущая версия .
Отредактировано 29.11.2021 10:57 Pauel . Предыдущая версия .
Re[5]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 20.11.21 03:24
Оценка: 59 (3)
Здравствуйте, Shmj, Вы писали:


S>Если оставил всего 1 команду Get-Variable — можно ли быть уверенным, что какими-то алиасами или хаками нельзя будет запустить процесс, получить доступ к содержимому файла или удалить его и т.д.? Не разбирались с этим?


это может подойдет? https://github.com/dynamicexpresso/DynamicExpresso

секьрность, + — и т.п. из коробки.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[14]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 24.11.21 01:56
Оценка: 21 (2) +1
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>А вот для парсинга выше лексем во втором случае есть специализированный неуниверсальный алгоритм, реализация которого проще, чем написание грамматики для выражений с приоритетами, не говоря уж о заталкивании ее в реальный генератор со всеми его тараканами. Ну просто потому что эти выражения с приоритетами описываются в BNF на редкость извратно.
Эмм. А что там особенно извратного? Пишется всё примерно так же, как и слышится. Стоит один раз увидеть реализацию, как всё становится предельно очевидно. По одной продукции на приоритет:
expr = add
add = mul '+' mul | mul '-' mul | mul 
mul = power '*' power | power '/' power | power '%' power | power
power = atom '^' atom | atom
atom = number | var | '-' atom | '(' expr ')'
number = [0-9]+
var = [a-zA-Z][a-zA-Z0-9]*

Всё. Вот вам выражения с тремя четырьмя приоритетами, 7 операторов. Хотите, чтобы я дописал семантические действия? И сравним, что проще — Пратт или PEG.
НС>И с Праттом почему то у генераторов не очень, 99% используют ДКА для лексера и LR или LL для того что выше. Исключение составляет тот парсер что я 5 лет назад писал на предыдущей работе и, вроде бы, Nitra. С другой стороны, для Пратта генератор и не нужен особо, он там интересен только как часть полноценного LL или LR генератора, в которой есть специальный хардкод именно для выражений.
Так нам же нужны ехать, а не шашечки. PEG парсеры не нуждаются в лексерах и едят практически готовую EBNF плюс собственно семантические правила. Наверное, по быстродействию Пратт выиграет, но для однострочных выражений нам это скорее всего будет неважно.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 24.11.2021 4:59 Sinclair . Предыдущая версия . Еще …
Отредактировано 24.11.2021 2:31 Sinclair . Предыдущая версия .
Re[17]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 19.11.21 09:18
Оценка: 12 (1) +2
Здравствуйте, vaa, Вы писали:

vaa>парсить можно обычным IndexOf.


Что не предложение от тебя, то перл.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[8]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 18.11.21 08:35
Оценка: +3
Здравствуйте, vaa, Вы писали:

НС>>Потому что тащить большой и тяжелый движок ради копеечной функциональности — с технической точки зрения безумие. Это как мешок картошки с дачи везти карьерным самосвалом на 200т.

vaa>Все уже реализовано, но нам нужен свой велосипед.

Что реализовано? Еще раз — тащить огромный движок ради смешной функциональности это бред.

НС>>Потому что правило может задаваться порльзователем, а не программистом.

vaa>ТС четко указал конкатенация строк, какой еще пользователь?

Который описывает формулу. ТС ничего не писал о том что формула статически фиксирована. И речь была не только про конкатенацию

Ну там конкатенация, добавление префикса, проверку на равенство строк и пр.

Это довольно частая задача — определение формулы вычисляемых полей пользователем.

НС>>И привет SQL injection?

vaa>Почему нельзя использовать параметризацию?

Потому что параметризация крайне ограничена по возможностям, там даже список толком передать нельзя. А уж произвольный оператор через параметр — вообще без шансов.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[20]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 23.11.21 05:55
Оценка: :)))
Здравствуйте, Sinclair, Вы писали:

S>https://dotnetfiddle.net/vPumI1


S>Пояснения нужны?


Да, чем может System.Console навредить системе? Про возможности рефлексии знаю.
попробуйте получить список файлов например из каталога C:\Windows
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 17.11.21 06:25
Оценка: 17 (2)
Здравствуйте, Shmj, Вы писали:
IronPython можно заюзать. синтаксис популярный. корку держит.
|     Method |              Mean |             Error |            StdDev |
|----------- |------------------:|------------------:|------------------:|
|     Script | 46,113,033.333 ns | 1,611,812.3684 ns | 4,727,166.6613 ns |
|   ByteCode |          4.228 ns |         0.2075 ns |         0.2390 ns |
| IronPython |     36,127.126 ns |       563.4038 ns |       527.0083 ns |

        [Benchmark]
        public object Script() => CSharpScript.EvaluateAsync("1 + 1").GetAwaiter().GetResult();

        [Benchmark]
        public object ByteCode() => (object)(1 + 1);

    static ScriptEngine engine = Python.CreateEngine();

        [Benchmark]
        public object IronPython() =>  engine.Execute("1 + 1");
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[17]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 22.11.21 18:24
Оценка: 15 (1) +1
Здравствуйте, vaa, Вы писали:

vaa>кроме юзингов еще референсы все это для каждого скрипта настраивается отдельно.


Статические референсы — не единственный способ загрузки сборок.

vaa>но вообще то это лишнее, юзинги в скрипте после компиляции все вроде по документации будут в св-вах юнита.


Нет, не будет никаких юсингов после компиляции, это в чистом виде синтаксический сахар.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re: Простой скрипт внутри приложения (в виде строки)
От: bnk СССР http://unmanagedvisio.com/
Дата: 16.11.21 22:25
Оценка: 11 (2)
Здравствуйте, Shmj, Вы писали:

S>Нужно чтобы приложение из базы данных брало простой скрипт в виде строки. Подставляло некоторые параметры туда. Что есть из готового?


https://github.com/microsoft/ClearScript

cs-script в принципе тоже нормальный, но намного медленее Google V8, если тебе склрость важна
Отредактировано 16.11.2021 22:33 bnk . Предыдущая версия .
Re[3]: Простой скрипт внутри приложения (в виде строки)
От: _NN_ www.nemerleweb.com
Дата: 19.11.21 06:48
Оценка: 10 (2)
Здравствуйте, Shmj, Вы писали:


S>Приходилось ли вам работать с песочницей PowerShell? Она полностью поддерживается в .Net Core? Могли бы подробнее ткнуть с чего начать?


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

Объект имеет свойство Commands куда можно либо добавить новые команды, либо убрать опасные.
Для тестов я создавал чистый InitialSessionState, копировал в него некоторые безопасные команды из реализации по умолчанию такие как Start-Sleep, а далее добавлял ту реализацию, что мне была нужна.

Для создания собственно PowerShell нужен RunSpaceFactory.CreateRunspace куда можно передать наш InitialSessionState, либо создать по умолчанию.

Также стоит отметить InitialSessionState.LanguageMode.
Свойство указывает вариант языка, который будет нам доступен.

В документации достаточно примеров, да и код PowerShell открыт покопаться: Creating an InitialSessionState

Единственная проблема с PowerShell это операции, которые не выглядят как в других языках, что нужно учитывать.
About comparison
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[19]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 20.11.21 08:37
Оценка: 10 (1) +1
Здравствуйте, vaa, Вы писали:

vaa>в каком смысле? чем плох встроенный поиск по строке перед вашим предложением по реализации стороннего алгоритма?


Начни с книжки с драконом.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[3]: Простой скрипт внутри приложения (в виде строки)
От: _NN_ www.nemerleweb.com
Дата: 17.11.21 18:08
Оценка: +2
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Здравствуйте, _NN_, Вы писали:


_NN>>PowerShell не подходит ?


НС>Тащить целиковый posh просто для вычисления простенького выражения? Камон, бро, это совсем уж аут оф здравый смысл. Если уж вот прям приспичило что то готовое — есть море небольших библиотек, ссылки на которые постят тут регулярно.


Сегодня выражение, завтра что-нибудь ещё понадобится.
Тут IronPython выше предлагали, он тоже немаленький.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[12]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 18.11.21 11:00
Оценка: :))
Здравствуйте, Sinclair, Вы писали:

S>Здравствуйте, Ночной Смотрящий, Вы писали:

НС>>Затаскивание полноценного языка ради вычисления формулы — это не решение задачи бизнеса, это банальнейшая халтура. Использование Питона в данном конкретном случае не имеет ни одного преимущества, и при этом привносит в проект огромное количество недостатков.
S>А то. "У меня была проблема, и я придумал решить её, втащив в программу Питон. Теперь у меня две проблемы".
Да какая проблема-то?
https://www.nuget.org/packages/IronPython/3.4.0-alpha1
500 разрабов в день так не считают.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[12]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 18.11.21 11:01
Оценка: +1 -1
Здравствуйте, vaa, Вы писали:

vaa>сегодня формула завтра if/else.


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

vaa>ну и еще вариант не писать парсер, а написать редактор визуальный




Эта безумная идея — прям болезнь новичков в программировании, особенно без профильного образования. Вкратце — нет, это намного сложнее в реализации и намного хуже по своим потребительским характеристикам. Плюсов у такого только один — можно реализовать человеку с нулевым CS бекграундом.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[13]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 18.11.21 11:03
Оценка: :))
Здравствуйте, Ночной Смотрящий, Вы писали:


НС>


Мы еще только разогреваемся, а вы уже за голову схватились
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[18]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 20.11.21 03:22
Оценка: :))
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Здравствуйте, vaa, Вы писали:


vaa>>парсить можно обычным IndexOf.


НС>Что не предложение от тебя, то перл.


в каком смысле? чем плох встроенный поиск по строке перед вашим предложением по реализации стороннего алгоритма?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[13]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 22.11.21 10:25
Оценка: +2
Здравствуйте, Max Mustermann, Вы писали:

S>>А то. "У меня была проблема, и я придумал решить её, втащив в программу Питон. Теперь у меня две проблемы".

MM>Это, конечно, очень остроумный ответ, но в предложеной альтернативе "напиши Пайтон на коленке сам и втащи его в программу" проблем явно чуть поболее.

Ты подменил задачу своим решением. Нет задачи воткнуть Пайтон, есть задача посчитать простое выражение. Если уж так пугает перспектива написания примитивного парсера — уже даже здесь дали ссылку на готовый.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[8]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.11.21 07:45
Оценка: +2
Здравствуйте, vaa, Вы писали:

НС>>>Тогда проще всего ознакомиться с алгоритмом Пратта и накидать нужный движочек за пару часов с нуля. Если время работы важнее времени старта — накинь еще пару часиков на реализацию простенького компилятора. В любом случае, за рабочий день, максимум два справишься.


S>>В наше время уже так не делают. Есть nuget, есть sof. Все что сверх того — то от лукавого.

vaa>Вот нашел код на питоне, правда не понял, как аргументы подавать на вход.

Никак, это не предусмотрено Здесь собственно демонстрация именно Пратта а не цельного решения. Во первых, нужно побольше действий, скобочки, переменные и числа, а во вторых, параметры нужно вставлять уже в готовое аст, иначе мулька смысла не имеет.
Что само ядро этого метода короткое, никто вобщем не сомневается. Сомнения есть в свойствах цельного солюшна. Грамматики нет, правила как ни крути всё равно рекурсивные, а раз так, то придется только догадываться о языке по его парсеру. С такими решениями первая замена на проекте дает проблему.
Re[23]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 26.11.21 20:40
Оценка: +1 -1
Здравствуйте, Ikemefula, Вы писали:

I>В целом, ты потратил много больше времени на форум, нежели на тот простецкий парсер по методу Пратта.


Дело не во времени а в мозговых ресурсах. Потратить время на расслабоне, просто удовлетворив свою потребность в общении — это не то же самое, что концентрированно что-то делать. После расслабона можно поработать — а вот когда потратил мозговые ресурсы — хрена с два.
Re[12]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 23.11.21 15:24
Оценка: 15 (1)
Здравствуйте, Ночной Смотрящий, Вы писали:

I>>Я уже попробовал, и нахожу рекурсив-децент и парсеры комбинаторов проще чем этот пратт.


НС>Ты точно пробовал реализовать Пратта? Потому что из топика у меня сложилось ощущение, что ты вообще не представляешь что это.


Точно. Взял статью Крокфорда и разобрался.

I>>Меня интересует не сам факт наличия тестов, а их количество.

НС>Идентично. Вне зависимости от того как написан парсер. Надо покрыть все возможные конструкции в любом случае.

В случае с библиотекой комбинаторов мне не надо покрывать тестами комбинаторы sequence, optional, rep и тд, все это покрыто тестами. Вроде бы очевидно.
Точно так же и с любой библиотекой — нет нужды дублировать её тесты.

I>>Нету потребности в сверлах, есть потребность в отверстиях. Поделись, как ты без грамматики собираешься поддерживать ну скажем iso-8601?

НС>iso-8601 это вообще лексер, при чем тут парсинг?

Я ж пишу — потребности в сверлах нет, т.к. нужны отверстия. Нужно разобрать содержимое колонки в бд, а там есть всё, а не только операторы, и вычислить. То есть, в нашем случае iso-8601 это часть нашего языка.

> Обычный ДКА по классике вполне справляется. Тут бы я точно велосипеды изобретать не стал, включая построение таких вещей на комбинаторных парсерах.


Что такое "обычный дка"? У меня например нет такой библиотеки "обычный дка". Кто выдаст код и юнит тесты для него? На мой взгляд комбинаторы куда проще дка.
Вот есть правило из odata abnf
SIGN = '-' / '+'
DIGIT = '0'/'1'/'2'/3'/'4'/'5'/'6'/'7'/'8'/'9'
decimal = [ SIGN ] 1*DIGIT [ "." 1*DIGIT ] [ "e" [ SIGN ] 1*DIGIT ]

код парсера, один в один повторяет грамматику, что дает возможность генерить код:
sign = or('-', '+')
digit = or('0','1','2',3','4','5','6','7','8','9')
decimal = sequence(sign, rep(1, digit), optional('.', rep(1, digit)), optional('e', sign, rep(1, digit)))

decimal('123.456 + 123.456') съест 123.456 и вернет чтото навроде ['123.456', ' + 123.456'].
покажи, как ты построишь дка для этого правила и что тебе для этого понадобится.

I>>Внезапно, если глянуть протокол odata, всё так и есть — abnf + приоритет операторов.

НС>В одате грамматика существенно сложнее чем просто выражения, полностью ее Пратт не покроет скорее всего, это не универсальное решение.

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

I>>Этот "нехилый бекграунд" дается на втором курсе, от силы — третьем.

НС>Это если этот самый второй курс есть. У тебя вот он есть?

Есть. Вообще, спустя 20 лет после университета мне пришлось реализовать парсер ОДАТА протокола. От унивеситетских знаний ничего не осталось. По ходу рефакторинга библиотечка парсер комбинатров выросла сама собой. Код компактный, пишется быстро, но я её выбросил и вернулся к recursive descent просто потому, что контроля над перформансом гораздо больше.

I>>Непонятно.

НС>Потому что ты не потрудился ознакомится с Праттом.

Телепатия тебя как всегда подводит.

I>>Почему ты решил, что речь только про операторы?

НС>Потому что ТС требуются просто несложные выражения, а не полноценные языки.

Так и выражения в odata это вообще говоря несложные, а по твоему "скорее всего не покроет"

I>>Ты просто в другой форме повторяешь "там всё просто".


НС>Потому что там на самом деле все просто. Ты попробуй.


Давно попробовал, и потому и излагаю своё видение. Тебя это не устраивает похоже.
Re[18]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.11.21 01:41
Оценка: 15 (1)
Здравствуйте, Ikemefula, Вы писали:

I>А может остановиться на твоей грамматике в 7 действий? Многовато работы выходит, по любому. Для сравнения алгоритмов должно хватить.

https://github.com/evilguest/StringExpressionParser/
Простая double арифметика. Можно пользоваться предопределёнными параметрами.
Собственно, вот граммматика https://github.com/evilguest/StringExpressionParser/blob/master/StringExpressionParser/Arithmetics.peg
Вот код, который готовит параметры x, y, z, разбирает строку, компилирует её в динамический делегат, и исполняет: https://github.com/evilguest/StringExpressionParser/blob/master/StringExpressionParser/Program.cs
Словарик сбоку я добавил из-за склероза — явно был такой готовый класс в BCL, но я забыл как он называется.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 25.11.2021 1:48 Sinclair . Предыдущая версия .
Re[12]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 23.11.21 16:39
Оценка: 12 (1)
Здравствуйте, Ночной Смотрящий, Вы писали:

Сейчас не 1961, а 2021. Писать вручную разбор выражений — ну, так себе.

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

Но при этом, естественно, сидеть и вручную выписывать конечные автоматы я бы тоже не стал. Нафига?
Я полностью согласен с https://tomassetti.me/parsing-in-csharp/ — писать свой парсер нужно только в тех случаях, когда никакие существующие не устраивают.
Берём готовый генератор парсеров, пишем для него грамматику, и поехали.
Вот, первое, что нашлось для PEG — https://github.com/otac0n/Pegasus . Выглядит вполне себе ок.

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

Даже если в проект придёт кто-то незнакомый с синтаксисом правил конкретного генератора парсеров, то скорее всего сможет расширить парсер по имеющемуся образцу.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[3]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 17.11.21 05:47
Оценка: 6 (1)
Здравствуйте, Shmj, Вы писали:

S>Насколько быстро оно работает, не создает ли файлов? Если на каждый запрос запускать такой скрипт — не сильно дорого?

работает со скоростью сишарпа, конечно же.
не создает.
что значит дорого?

BenchmarkDotNet=v0.13.1, OS=Windows 10.0.19043.1348 (21H1/May2021Update)
Intel Core i3-6100U CPU 2.30GHz (Skylake), 1 CPU, 4 logical and 2 physical cores
.NET SDK=6.0.100
  [Host]     : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT
  DefaultJob : .NET 6.0.0 (6.0.21.52210), X64 RyuJIT


|   Method |               Mean |             Error |            StdDev |
|--------- |-------------------:|------------------:|------------------:|
|   Script | 40,965,881.4433 ns | 1,100,732.4731 ns | 3,193,424.4939 ns |
| ByteCode |          0.0096 ns |         0.0049 ns |         0.0041 ns |


using System;
using static System.Console;
using System.Security.Cryptography;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using Microsoft.CodeAnalysis.CSharp.Scripting;

public class ScriptVsByteCode {

        [Benchmark]
        public int Script() => (int)CSharpScript.EvaluateAsync("1 + 1").Result;

        [Benchmark]
        public int ByteCode() => 1 + 1;
}

static class Program {
    static void Main() {
        var summary = BenchmarkRunner.Run<ScriptVsByteCode>();
    }
}
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[5]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 18.11.21 02:24
Оценка: 6 (1)
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>IronPython и CS script тащить — такой же бред.


Почему нет? питон самый популярный язык на сегодня. легкий в изучении.
вообще не понятно конечно зачем ТС для соединения строк выполнение скриптов. Это же банальная интерполяция.
Проблема изначально в постановке задачи.
Нам известно что выражение хранится в текстовом поле.
если там написано: "'AAA' + 'BBBB'" то почему сразу не написать 'AAABBBB'?
если там написано: "$A + $B" где А и B некоторые переменные, то почему не использовать стандартный C# $"{A}{B}"?
если a и b поля таблицы то это вообще решается на уровне SQL.
В общем, ТС, АУ!
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: _NN_ www.nemerleweb.com
Дата: 09.12.21 22:06
Оценка: 5 (1)
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, _NN_, Вы писали:


_NN>>Да.

_NN>>Это контролируется через LanguageMode.

S>Если не секрет, какие вы настройки примерно использовали? Достаточно работы Get-Variable и операций со строками.


Например так.
Можно скопировать уже готовые команды или добавлять свои.

using System;
using System.Linq;
using System.Management.Automation;
using System.Management.Automation.Runspaces;

class A
{
    public static void Main()
    {
        // Full 
        InitialSessionState fullIss = InitialSessionState.CreateDefault();
        
        // No commands !
        InitialSessionState iss = InitialSessionState.CreateRestricted(SessionCapabilities.Language); 
        Console.WriteLine(iss.Commands.Count); // 0

        // No external calls
        iss.LanguageMode = PSLanguageMode.ConstrainedLanguage;

        // Add Get-Variable
        var getVariableCmdlet = fullIss.Commands.First(c => c.Name == "Get-Variable");
        iss.Commands.Add(getVariableCmdlet);

        // Only Get-Variable exists
        foreach (var c in iss.Commands) Console.WriteLine(c.Name);

        // Run script
        PowerShell ps = PowerShell.Create(iss);
        var r = ps.AddScript(@"$a = 'x,y';
$b = (get-variable a).Value.Split(',');
return $b;
");
        foreach (var x in r.Invoke())
        {
            Console.WriteLine(x);
        }

    }
}
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[4]: Простой скрипт внутри приложения (в виде строки)
От: Mihas  
Дата: 17.11.21 07:38
Оценка: 1 (1)
Здравствуйте, vaa, Вы писали:

vaa>можно еще попробовать

vaa>https://ironpython.net/download/
Из подводных камней:
— запуск скрипта требует времени на инициализацию (когда-то, когда я применял, оно измерялось единицами миллисекунд, если не десятками)
— стандартные классы (типа string) имеют свою питоновскую реализацию, при том что остальные дотнетовские классы как родные
Re[21]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 14.12.21 08:49
Оценка: 1 (1)
Здравствуйте, Shmj, Вы писали:

НС>>Начни с книжки с драконом.

S>Можно ткнуть в книгу?

https://www.ozon.ru/product/kompilyatory-printsipy-tehnologii-i-instrumentariy-148627197/?sh=OfDwl_nr
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[10]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 18.11.21 09:03
Оценка: :)
Здравствуйте, vaa, Вы писали:

НС>>Что реализовано? Еще раз — тащить огромный движок ради смешной функциональности это бред.

vaa>наверно, каждому свое. кто-то пишет код, кто-то решает задачи бизнеса.

Затаскивание полноценного языка ради вычисления формулы — это не решение задачи бизнеса, это банальнейшая халтура. Использование Питона в данном конкретном случае не имеет ни одного преимущества, и при этом привносит в проект огромное количество недостатков.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[11]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 18.11.21 10:57
Оценка: +1
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Затаскивание полноценного языка ради вычисления формулы — это не решение задачи бизнеса, это банальнейшая халтура. Использование Питона в данном конкретном случае не имеет ни одного преимущества, и при этом привносит в проект огромное количество недостатков.


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

public class Concat {
 public string First {get;set;}
 public string Second {get;set;}
 public string Result => First + Second;    
}
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[11]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 18.11.21 13:56
Оценка: +1
Здравствуйте, Sharov, Вы писали:


S>Если это сервис, то странное и очень плохое решение, но еще терпимо, а если разворачивать

S>у заказчика -- один маленький exe на шарпе и огромный питон. Ну это бред же, т.е. сразу
S>надо на питоне писать тогда и все.
или заставить пользователя(тут не уверен. т.к. автор не комментирует наши споры) изучать сишарп.
питон вполне себе отличный способ добавить скриптов в программу. раз даже малышей учат ему.
видел встройку и на паскале и на java(script)(saleforce).
не вижу проблем.
а вот писать свой Интерпрета́тор. это сначала надо придумать грамматику, потом правила, потом реализовать, потом отлаживать,
а через год поймешь что написал кривой лисп
Каждый должен написать свой компилятор. недавно встречал такое выражение.

UPDATE: а потом чел уволился...
☭ ✊ В мире нет ничего, кроме движущейся материи.
Отредактировано 18.11.2021 14:13 Разраб . Предыдущая версия .
Re: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 18.11.21 14:35
Оценка: +1
Здравствуйте, Shmj, Вы писали:

S>Кто что посоветует.


S>Нужно чтобы приложение из базы данных брало простой скрипт в виде строки. Подставляло некоторые параметры туда. Что есть из готового?


S>Есть какой-то https://github.com/oleg-shilo/cs-script Но какой-то громоздкий. Не ясно создает ли он временные файлы — желательно без них.


дерзай https://github.com/IronyProject/Irony/wiki
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[16]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 19.11.21 07:49
Оценка: -1
Здравствуйте, Shmj, Вы писали:

S>Раньше можно было создать AppDomain с установленными разрешениями. В .Net Core эту возможность убрали — только полный доступ ко всему

если задача сделать безопасно, то делай как предлагал смотрящий — рукописный парсер и интерпретатор. парсить можно обычным IndexOf.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Простой скрипт внутри приложения (в виде строки)
От: BlackEric http://black-eric.lj.ru
Дата: 20.11.21 15:17
Оценка: :)
Здравствуйте, Shmj, Вы писали:

S>Кто что посоветует.


S>Нужно чтобы приложение из базы данных брало простой скрипт в виде строки. Подставляло некоторые параметры туда. Что есть из готового?


S>Есть какой-то https://github.com/oleg-shilo/cs-script Но какой-то громоздкий. Не ясно создает ли он временные файлы — желательно без них.


C# + Roslyn?
Скриптинг в C# или динамическое выполнение в runtime
https://github.com/BlackEric001
Re[15]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.11.21 12:53
Оценка: +1
Здравствуйте, vaa, Вы писали:
vaa>про питон не знаю точно, но если импорты возможны только на уровне модуля. то мы можем обернуть выражение в функцию-пустышку.
Смелая идея. Я про питон тоже не знаю точно, но в общем случае обрезать функции языка бывает сложнее, чем добавить.
vaa>в сишапр-скрипте тем более единицу компиляции можно проверить юзинги по черному списку.
Да вы батенька шутник. Юзинги в шарпе вообще-то никак не влияют на доступ к коду — просто надо будет писать выражения чуть подлиннее.
vaa>вообщем, помните супер-бразуер от мс ?
vaa>даже с их мощностями не хватило вывезти с нуля.
vaa>для того и придумали повторное использование. разве нет?
Эмм, что вы имеете в виду? Вы всерьёз полагаете, что парсер алгебраических выражений над строками сопоставим по сложности с веб-браузером?
Это, мягко говоря, не так.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[16]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 22.11.21 13:28
Оценка: :)
Здравствуйте, Sinclair, Вы писали:

S>Да вы батенька шутник. Юзинги в шарпе вообще-то никак не влияют на доступ к коду — просто надо будет писать выражения чуть подлиннее.

кроме юзингов еще референсы все это для каждого скрипта настраивается отдельно.
фулкволитинэйм лекго отсечь банальным blacklist.ForEach( ...=> source.Replace(....
но вообще то это лишнее, юзинги в скрипте после компиляции все вроде по документации будут в св-вах юнита.

S>Эмм, что вы имеете в виду? Вы всерьёз полагаете, что парсер алгебраических выражений над строками сопоставим по сложности с веб-браузером?

Как вы сами выразились "сотня функций", где сотня там и две. когда вам ставят задачу: "да там надо только строки складывать" я бы сразу напрягься, потому что потом нужно будет выделенного синьора держать для внедрения фичей уже давно имеющихся в куче готовых компонентов.
Грубо говоря, вот так.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Отредактировано 22.11.2021 13:29 Разраб . Предыдущая версия .
Re[6]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 23.11.21 07:52
Оценка: +1
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>>>Т.е. просто одно несложное выражение?

S>>Типа того.

НС>Тогда проще всего ознакомиться с алгоритмом Пратта и накидать нужный движочек за пару часов с нуля.


Для несложных выражений проще взять чтото более мирное, обычные parser combinators например.
Я бы вообще начал с польской записи, это уровень студента-первокурсника.
В любом случае сначала надо будет построить хоть какуюто грамматику. Ошибки в этой части дадут месяцы и годы багфикса.
То есть "накидать за пару часов" это даже на прототип не потянет, если не было опыта в парсинге.
Re[17]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 24.11.21 13:57
Оценка: -1
Здравствуйте, Sinclair, Вы писали:

НС>>Ну и сравни это просто со списком операторов в порядке приоритета.

S>Эмм, пока у нас нет готовой библиотеки, которая умеет Пратт

https://github.com/atifaziz/Gratt
Там 400 строк с огромными комментариями и пустотами, причем непосредственно алгоритм в сумме ну может строк 60. Камон, может мы еще и какой нибудь поиск подстроки в строке будем отдельной либой тянуть, в JS такое любят?
Сравни с любой реализацией PEG на выбор.
Вы просто почему то упорно считаете что Пратт это такой навороченный рокетсайнс типа какого нибудь GLL, PEG или комбинатора, и воспринимаете мои слова как будто я предлагаю этих монстров руками писать. В то время как Пратт это полный примитив, стократ проще не только вышепреречисленных, но и даже банальных регексов. Сложность, реально, уровня поиска подстроки или преобразования числа в строку.

S>Ну, и чисто академический вопрос — как Пратт обрабатывает унарные операторы? Особенно если оператор совпадает по лексеме с бинарным оператором?


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

НС>>Ну как не нуждаются. Граница лексер/парсер не нечто фундаментальное и жестко фиксированное.

S>Так и не нуждаются. Обычно PEG парсеры едут прямо по потоку символов.

Когда плевать на перф — да. А когда не плевать — появляются вполне честные лексеры с регулярками.

S>Производительность не мерил, спорить не возьмусь.


Тут можно ничего не мерить. Минимизированный ДКА для классических цифровых автоматов это самый оптимальный алгоритм (за исключением отдельных граничных случаев).

S>Но, повторюсь, в данной задаче у нас явно на первом месте понятность грамматики и надёжность реализации.


И поэтому куча рекурсивных правил проще простого сортированного списка операторов? Ну ОК, я тебя понял.

S>Давайте может всё же сделаем забег?


Не, столько времени я не готов на этот спор тратить, сорри.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[18]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.11.21 14:44
Оценка: +1
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Сложность, реально, уровня поиска подстроки или преобразования числа в строку.


Это неадекватное преувеличение. Интересует как раз сложность всего решения, а не только одной функции. Самый минимум, который требуется для pratt парсер будет буквально раз в пять больше, чем преобразование числа в строку.
А сверх этого надо таки операторы запилить и сам лексер.
Re[20]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 25.11.21 01:47
Оценка: +1
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>Ну что за шулерство? Там АСТ, размер которого не зависит от типа парсера. Сам парсер не в тестах, а в файле Parser.cs.
Сам парсер — это хорошо. Но нас же интересует прикладная задача — сколько кода нужно написать для того, чтобы взлетела конкретная грамматика.
Тесты — это оно и есть: тот код, который нужно написать поверх алгоритма.
Там, конечно, можно сократить — за счёт использования готовых AST классов из System.Linq.Expressions. Но всё равно с 39 строчками PEG это сравнить не получится — потому что Parselets, которые в PEG записаны внутри грамматики, надо писать руками.

НС>Нет.

В том-то и дело. PEG парсер для конкретной грамматики я написал вчера за полчаса. С Праттом так, похоже, не выйдет.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[20]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.11.21 04:57
Оценка: -1
Здравствуйте, Ночной Смотрящий, Вы писали:

S>>Простите, но где именно там 400 строк?

S>>Я вот вижу, что простейшая арифметика занимает 500 строк.

НС>Ну что за шулерство? Там АСТ, размер которого не зависит от типа парсера. Сам парсер не в тестах, а в файле Parser.cs.


Эдак можно сказать, что recursive descent самый простой и короткий — кода вообще ноль, а все остальное "Там АСТ, размер которого не зависит от типа парсера"
Re[2]: Простой скрипт внутри приложения (в виде строки)
От: RonWilson Россия  
Дата: 25.11.21 07:19
Оценка: :)
Здравствуйте, BlackEric, Вы писали:

BE>C# + Roslyn?

BE>Скриптинг в C# или динамическое выполнение в runtime

Можно же куда проще: COM с IActiveScript, а там VBScript
Re[9]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 25.11.21 08:52
Оценка: +1
Здравствуйте, RonWilson, Вы писали:

RW>Вроде ТС и нужна одна строчка, я же не настаиваю на VBS, просто добавил в копилку, вдруг он скажет — "О! То что надо!! Всю жизнь мечтал о VBS"

Да, можно по старинке, при добавлении скрипта можно проверять, что он однострочный, не превышает 100 символов, не содержит слов исключений, типа Invoke, Delete и т.п.
хотя говорят в перле можно и более коротким выражением делов наделать.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[23]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 26.11.21 19:35
Оценка: -1
Здравствуйте, Ikemefula, Вы писали:

I>В целом, ты потратил много больше времени на форум, нежели на тот простецкий парсер по методу Пратта.


Ну не много больше, но сопопставимо, и?
На форуме я отвлекаюсь от работы, а не пытаюсь работать еще.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 16.11.21 20:41
Оценка:
Кто что посоветует.

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

Есть какой-то https://github.com/oleg-shilo/cs-script Но какой-то громоздкий. Не ясно создает ли он временные файлы — желательно без них.
Re: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 17.11.21 03:48
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Кто что посоветует.


S>Нужно чтобы приложение из базы данных брало простой скрипт в виде строки. Подставляло некоторые параметры туда. Что есть из готового?


Core?
#r "nuget: Microsoft.CodeAnalysis.CSharp.Scripting"
open Microsft.CodeAnalysis.CSharp.Scripting
let result:obj = CSharpScript.EvaluateAsync("1 + 1").Result
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[2]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 17.11.21 05:04
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>Core?

vaa>
vaa>#r "nuget: Microsoft.CodeAnalysis.CSharp.Scripting"
vaa>open Microsft.CodeAnalysis.CSharp.Scripting
vaa>let result:obj = CSharpScript.EvaluateAsync("1 + 1").Result  
vaa>


Насколько быстро оно работает, не создает ли файлов? Если на каждый запрос запускать такой скрипт — не сильно дорого?
Re[2]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 17.11.21 05:28
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>https://github.com/microsoft/ClearScript


bnk>cs-script в принципе тоже нормальный, но намного медленее Google V8, если тебе склрость важна


Эта штука при запуске требует нейтивные ClearScriptV8.linux-x64.so

Нет ли чего-нибудь без таких зависимостей сложных?
Re[3]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 17.11.21 05:55
Оценка:
Здравствуйте, Shmj, Вы писали:

можно еще попробовать
https://ironpython.net/download/
и это
https://github.com/IronScheme/IronScheme
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 17.11.21 07:08
Оценка:
Здравствуйте, Shmj, Вы писали:

|     Method |              Mean |             Error |            StdDev |            Median |
|----------- |------------------:|------------------:|------------------:|------------------:|
|     Script | 38,895,082.000 ns | 1,158,899.6864 ns | 3,417,041.8728 ns | 38,503,800.000 ns |
|   ByteCode |          4.397 ns |         0.2812 ns |         0.7932 ns |          4.029 ns |
| IronPython |     36,691.971 ns |       733.0558 ns |     1,624.4011 ns |     36,369.061 ns |
| IronScheme | 15,918,611.707 ns | 2,620,438.8590 ns | 7,726,423.0989 ns | 15,823,650.391 ns |


Ожидаемо, тк вызывался через расширение, лень изучать:
        [Benchmark]
        public object Script() => CSharpScript.EvaluateAsync("1 + 1").GetAwaiter().GetResult();

        [Benchmark]
        public object ByteCode() => (object)(1 + 1);

    static ScriptEngine engine = Python.CreateEngine();

        [Benchmark]
        public object IronPython() =>  engine.Execute("1 + 1");

        [Benchmark]
        public object IronScheme() => "(+ 1 1)".Eval();
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 17.11.21 09:32
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Нужно чтобы приложение из базы данных брало простой скрипт в виде строки. Подставляло некоторые параметры туда. Что есть из готового?


Что скрипт должен уметь?
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[2]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 17.11.21 10:24
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

S>>Нужно чтобы приложение из базы данных брало простой скрипт в виде строки. Подставляло некоторые параметры туда. Что есть из готового?

НС>Что скрипт должен уметь?

Операции со строками, которые есть даже в самых простых скриптовых языках. Ну там конкатенация, добавление префикса, проверку на равенство строк и пр.
Отредактировано 17.11.2021 10:25 Shmj . Предыдущая версия .
Re[3]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 17.11.21 10:47
Оценка:
Здравствуйте, Shmj, Вы писали:

S>>>Нужно чтобы приложение из базы данных брало простой скрипт в виде строки. Подставляло некоторые параметры туда. Что есть из готового?

НС>>Что скрипт должен уметь?
S>Операции со строками, которые есть даже в самых простых скриптовых языках. Ну там конкатенация, добавление префикса, проверку на равенство строк и пр.

Т.е. просто одно несложное выражение?
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[4]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 17.11.21 11:22
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Т.е. просто одно несложное выражение?


Типа того.
Re[6]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 17.11.21 12:35
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Тогда проще всего ознакомиться с алгоритмом Пратта и накидать нужный движочек за пару часов с нуля. Если время работы важнее времени старта — накинь еще пару часиков на реализацию простенького компилятора. В любом случае, за рабочий день, максимум два справишься.


В наше время уже так не делают. Есть nuget, есть sof. Все что сверх того — то от лукавого.
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 17.11.21 13:11
Оценка:
Здравствуйте, Shmj, Вы писали:

НС>>Тогда проще всего ознакомиться с алгоритмом Пратта и накидать нужный движочек за пару часов с нуля. Если время работы важнее времени старта — накинь еще пару часиков на реализацию простенького компилятора. В любом случае, за рабочий день, максимум два справишься.

S>В наше время уже так не делают.

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

S>Есть nuget, есть sof. Все что сверх того — то от лукавого.


Тебе шашечки или ехать?
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re: Простой скрипт внутри приложения (в виде строки)
От: _NN_ www.nemerleweb.com
Дата: 17.11.21 17:02
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Кто что посоветует.


S>Нужно чтобы приложение из базы данных брало простой скрипт в виде строки. Подставляло некоторые параметры туда. Что есть из готового?


S>Есть какой-то https://github.com/oleg-shilo/cs-script Но какой-то громоздкий. Не ясно создает ли он временные файлы — желательно без них.


PowerShell не подходит ?
Есть возможность полного контроля песочницы если надо.
Как язык есть некоторые специфичные моменты, зато легко и просто встраивается и тестируется.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: bnk СССР http://unmanagedvisio.com/
Дата: 17.11.21 17:07
Оценка:
Здравствуйте, Shmj, Вы писали:

НС>>Тогда проще всего ознакомиться с алгоритмом Пратта и накидать нужный движочек за пару часов с нуля. Если время работы важнее времени старта — накинь еще пару часиков на реализацию простенького компилятора. В любом случае, за рабочий день, максимум два справишься.


S>В наше время уже так не делают. Есть nuget, есть sof. Все что сверх того — то от лукавого.


Попробуй ещё загуглить на гитхабе по ключевым словам. Если увидишь иероглифы, это скорее всего то что тебе нужно. Китайцы не стесняются самостоятельно код писать.
Re[2]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 17.11.21 18:06
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>PowerShell не подходит ?


Тащить целиковый posh просто для вычисления простенького выражения? Камон, бро, это совсем уж аут оф здравый смысл. Если уж вот прям приспичило что то готовое — есть море небольших библиотек, ссылки на которые постят тут регулярно.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[4]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 17.11.21 18:13
Оценка:
Здравствуйте, _NN_, Вы писали:

НС>>Тащить целиковый posh просто для вычисления простенького выражения? Камон, бро, это совсем уж аут оф здравый смысл. Если уж вот прям приспичило что то готовое — есть море небольших библиотек, ссылки на которые постят тут регулярно.

_NN>Сегодня выражение, завтра что-нибудь ещё понадобится.

Или не понадобится. А какашку ты уже втащил, ее теперь поддерживать.

_NN>Тут IronPython выше предлагали, он тоже немаленький.


IronPython и CS script тащить — такой же бред.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 18.11.21 08:30
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:



НС>Потому что тащить большой и тяжелый движок ради копеечной функциональности — с технической точки зрения безумие. Это как мешок картошки с дачи везти карьерным самосвалом на 200т.

Все уже реализовано, но нам нужен свой велосипед.



НС>Потому что правило может задаваться порльзователем, а не программистом.


ТС четко указал конкатенация строк, какой еще пользователь?


НС>И привет SQL injection?

Почему нельзя использовать параметризацию? https://techcommunity.microsoft.com/t5/sql-server/dynamic-sql-amp-sql-injection/ba-p/383196
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[9]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 18.11.21 08:52
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Что реализовано? Еще раз — тащить огромный движок ради смешной функциональности это бред.

наверно, каждому свое. кто-то пишет код, кто-то решает задачи бизнеса.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[6]: Простой скрипт внутри приложения (в виде строки)
От: Sharov Россия  
Дата: 18.11.21 13:43
Оценка:
Здравствуйте, vaa, Вы писали:

НС>>IronPython и CS script тащить — такой же бред.

vaa>Почему нет? питон самый популярный язык на сегодня. легкий в изучении.

Зачем тогда на C# писать, почему сразу не взять питон?
Кодом людям нужно помогать!
Re[10]: Простой скрипт внутри приложения (в виде строки)
От: Sharov Россия  
Дата: 18.11.21 13:46
Оценка:
Здравствуйте, vaa, Вы писали:

НС>>Что реализовано? Еще раз — тащить огромный движок ради смешной функциональности это бред.

vaa>наверно, каждому свое. кто-то пишет код, кто-то решает задачи бизнеса.

Если это сервис, то странное и очень плохое решение, но еще терпимо, а если разворачивать
у заказчика -- один маленький exe на шарпе и огромный питон. Ну это бред же, т.е. сразу
надо на питоне писать тогда и все.
Кодом людям нужно помогать!
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 18.11.21 13:49
Оценка:
Здравствуйте, Sharov, Вы писали:

S>Зачем тогда на C# писать, почему сразу не взять питон?


вопрос был задан конкретный: что-то готовое под C#.
я предложил несколько вариантов, в том числе на C#.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[8]: Простой скрипт внутри приложения (в виде строки)
От: Sharov Россия  
Дата: 18.11.21 13:51
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>вопрос был задан конкретный: что-то готовое под C#.

vaa>я предложил несколько вариантов, в том числе на C#.

Объяснили, что слишком тяжеловесное решение. Полно всяких простейших парсеров, на хабре
народ регулярно делает и т.д. Для начала самое то. А дальше -- "будет день, будет пища".
Кодом людям нужно помогать!
Re[2]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 18.11.21 16:01
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>дерзай https://github.com/IronyProject/Irony/wiki


Да, выше его уже рекомендовали. Решил для универсальности его и заюзать. Вроде пока особых проблем не было.

Скипт не для внешних пользователей, так что вопрос безопасности не стоит остро.
Re[2]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 19.11.21 04:46
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>Core?

vaa>
vaa>#r "nuget: Microsoft.CodeAnalysis.CSharp.Scripting"
vaa>open Microsft.CodeAnalysis.CSharp.Scripting
vaa>let result:obj = CSharpScript.EvaluateAsync("1 + 1").Result  
vaa>


Вот, кстати, можно ли его ограничить, чтобы ничего кроме заданных операций нельзя было выполнить?
Re[4]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 19.11.21 04:47
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>Здравствуйте, Shmj, Вы писали:

vaa>IronPython можно заюзать. синтаксис популярный. корку держит.

Вот только вопрос безопасности все-таки приходится рассмотреть. Можно ли как-то ограничить, чтобы никакого зла нельзя было сделать через этот скрипт?
Re[13]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 19.11.21 04:58
Оценка:
Здравствуйте, vaa, Вы писали:

S>>А то. "У меня была проблема, и я придумал решить её, втащив в программу Питон. Теперь у меня две проблемы".

vaa>Да какая проблема-то?
vaa>https://www.nuget.org/packages/IronPython/3.4.0-alpha1
vaa>500 разрабов в день так не считают.

Все же стал вопрос безопасности — можно запретить запуск скриптов, которые грех будут делать?
Re[2]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 19.11.21 06:20
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>PowerShell не подходит ?

_NN>Есть возможность полного контроля песочницы если надо.

Да, основная проблема с чем столкнулся — песочница. Запускать скрипт который может все (в т.ч. создавать файлы, читать файлы и отправлять через сеть, запускать процессы и т.д.) — как то совсем тупо.

Приходилось ли вам работать с песочницей PowerShell? Она полностью поддерживается в .Net Core? Могли бы подробнее ткнуть с чего начать?
Re[12]: Простой скрипт внутри приложения (в виде строки)
От: удусекшл  
Дата: 19.11.21 07:03
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>а через год поймешь что написал кривой лисп


Лисп я за денёк накидал как-то
Re[14]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 19.11.21 07:34
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Все же стал вопрос безопасности — можно запретить запуск скриптов, которые грех будут делать?


освятить сервак можно.
сильные доспехи предлагали вместе с песочницей.
в сишарпе можно методы помечать аттрибутами безопасности. они что-то могут контролировать типа доступа к файлам. но это не точно. нужно проверять.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[15]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 19.11.21 07:40
Оценка:
Здравствуйте, vaa, Вы писали:

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


Раньше можно было создать AppDomain с установленными разрешениями. В .Net Core эту возможность убрали — только полный доступ ко всему
Re[13]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 19.11.21 07:41
Оценка:
Здравствуйте, удусекшл, Вы писали:

У>Здравствуйте, vaa, Вы писали:


vaa>>а через год поймешь что написал кривой лисп


У>Лисп я за денёк накидал как-то


хотел кстати ТС предложить. запустить лисп рядом с аспнетом и по сокету выполнять код. делов раз плюнуть.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[16]: Простой скрипт внутри приложения (в виде строки)
От: Serginio1 СССР https://habrahabr.ru/users/serginio1/topics/
Дата: 19.11.21 08:13
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, vaa, Вы писали:


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


S>Раньше можно было создать AppDomain с установленными разрешениями. В .Net Core эту возможность убрали — только полный доступ ко всему


Ну проще это все решить запуском процесса под другим пользоваелем
https://habr.com/ru/post/323096/
и солнце б утром не вставало, когда бы не было меня
Re[4]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 19.11.21 13:18
Оценка:
Здравствуйте, _NN_, Вы писали:

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

_NN>В принципе ничего сложного здесь нет.
_NN>Есть InitialSessionState
_NN>Его можно создать либо по умолчанию со всеми командами, либо полностью пустым.

Если оставил всего 1 команду Get-Variable — можно ли быть уверенным, что какими-то алиасами или хаками нельзя будет запустить процесс, получить доступ к содержимому файла или удалить его и т.д.? Не разбирались с этим?
Re[5]: Простой скрипт внутри приложения (в виде строки)
От: _NN_ www.nemerleweb.com
Дата: 20.11.21 09:11
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, _NN_, Вы писали:


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

_NN>>В принципе ничего сложного здесь нет.
_NN>>Есть InitialSessionState
_NN>>Его можно создать либо по умолчанию со всеми командами, либо полностью пустым.

S>Если оставил всего 1 команду Get-Variable — можно ли быть уверенным, что какими-то алиасами или хаками нельзя будет запустить процесс, получить доступ к содержимому файла или удалить его и т.д.? Не разбирались с этим?


Да.
Это контролируется через LanguageMode.
http://rsdn.nemerleweb.com
http://nemerleweb.com
Re[6]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 21.11.21 20:26
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Да.

_NN>Это контролируется через LanguageMode.

А где-то есть пример реализации песочницы?

Я не достаточно хорошо знаю PowerShell и все с ним связанное — как гарантировать что все учтено?
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 22.11.21 02:21
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Я не достаточно хорошо знаю PowerShell и все с ним связанное — как гарантировать что все учтено?

Никак. Инфобез, понимаешь! Объяви награду за поиск уязвимостей.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[8]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 22.11.21 03:34
Оценка:
Здравствуйте, vaa, Вы писали:

S>>Я не достаточно хорошо знаю PowerShell и все с ним связанное — как гарантировать что все учтено?

vaa>Никак. Инфобез, понимаешь! Объяви награду за поиск уязвимостей.

Ну хотя бы в теории — какую версию языка выбрать? Если Restricted выбираю — вообще ничего не работает, даже со всеми командами.
Re[9]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 22.11.21 05:38
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Ну хотя бы в теории — какую версию языка выбрать? Если Restricted выбираю — вообще ничего не работает, даже со всеми командами.

не пользовал исчадие ада под названием пауэршэл. только если прям никак без него. например в батнике создать архив или распаковать.
хотя и тут зачастую проще скопировать что-то типа 7z.
по теме: гарантию безопасности дать никто не может. максимум определить допустимый уровень угроз согласно методике.
т.е. что случится если скрипт выйдет из под контроля. какие данные и в каком масштабе могут пострадать.
2е это недокументированные возможности. опять же есть известные. тут все зависит от профессионализма специалиста по ИБ. и есть те что еще не известны.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[9]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 22.11.21 05:53
Оценка:
Здравствуйте, Shmj, Вы писали:
S>Ну хотя бы в теории — какую версию языка выбрать? Если Restricted выбираю — вообще ничего не работает, даже со всеми командами.
вот хороший пример. проверка using-ов https://mikecodes.net/2020/05/11/in-app-scripts-with-c-roslyn/
не уверен достаточно ли этого. можно еще исходный текст проверить.
чем диманикэкспрессо не угодил? там как раз только выражения. никаких new и проч.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[6]: Простой скрипт внутри приложения (в виде строки)
От: Flem1234  
Дата: 22.11.21 07:45
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Здравствуйте, Shmj, Вы писали:


НС>>>Т.е. просто одно несложное выражение?

S>>Типа того.

НС>Тогда проще всего ознакомиться с алгоритмом Пратта и накидать нужный движочек за пару часов с нуля. Если время работы важнее времени старта — накинь еще пару часиков на реализацию простенького компилятора. В любом случае, за рабочий день, максимум два справишься.


Эм, по словам "алгоритм Пратта" гуглится "поиск подстроки в строке". Смысл совета не ясен — предлагается писать движок с одной функцией — замены строки?
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 22.11.21 09:02
Оценка:
Здравствуйте, Flem1234, Вы писали:

F>Эм, по словам "алгоритм Пратта" гуглится "поиск подстроки в строке". Смысл совета не ясен — предлагается писать движок с одной функцией — замены строки?


https://en.wikipedia.org/wiki/Operator-precedence_parser#Pratt_parsing
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[6]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 22.11.21 09:39
Оценка:
Здравствуйте, _NN_, Вы писали:

_NN>Да.

_NN>Это контролируется через LanguageMode.

Если не секрет, какие вы настройки примерно использовали? Достаточно работы Get-Variable и операций со строками.
Re[10]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 22.11.21 09:40
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>чем диманикэкспрессо не угодил? там как раз только выражения. никаких new и проч.


Угодил. Пока наиболее подходящее. Просто для интереса спрашиваю — может еще пригодится, мало ли. Человек работал с ним и все знает.
Re[12]: Простой скрипт внутри приложения (в виде строки)
От: Max Mustermann  
Дата: 22.11.21 10:08
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>А то. "У меня была проблема, и я придумал решить её, втащив в программу Питон. Теперь у меня две проблемы".


Это, конечно, очень остроумный ответ, но в предложеной альтернативе "напиши Пайтон на коленке сам и втащи его в программу" проблем явно чуть поболее.
Re[13]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 22.11.21 10:51
Оценка:
Здравствуйте, Max Mustermann, Вы писали:
MM>Это, конечно, очень остроумный ответ, но в предложеной альтернативе "напиши Пайтон на коленке сам и втащи его в программу" проблем явно чуть поболее.
Ок, я разверну.
В задачах, которые на форумах формулируются как "нам тут нужно уметь вычислять заданные пользователем формулы с параметрами", обычно подразумевается сразу несколько вещей.
Например, что пользователи фичи разделяются на два непересекающихся лагеря — благонадёжных непрофессионалов, и высококвалифицированных злоумышленников.
При этом обычно от формул ожидается гарантия вычислимости за конечное время и память. А вот Тьюринг-полнота, напротив, нужна крайне редко.

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

Например, как вы гарантируете, что питоновый однострочник не зацикливается? Будете запускать питон-машину с таймаутом? Или будете проблему останова решать для каждой формулы?
Или, скажем, что помешает "пользователю" втащить в свою формулу IO-пакеты, и испоганить окружение в сервере приложений, работая под привилегиями системного аккаунта?

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

К тому же, рукопашная реализация позволяет использовать различные стратегии кэширования — то есть при повторном исполнении таких формул (а их, возможно, надо будет применять к миллиону строк таблицы) мы получим перформанс не хуже, чем у материнского приложения.
А питон или павершелл будут тратить секунды на каждое расчехление перед исполнением формулы.

Опять таки: если бы мы говорили про какую-то более другую систему, типа "мы тут пишем документооборот, и хотим давать пользователям писать императивные обработчики событий с богатым набором возможностей", то втаскивание готового скриптового движка имело бы больший смысл. Ну, потому что написать нормальный императивный ЯП с внятной диагностикой ошибок потребует больше, чем пары вечеров. И велики риски получить в итоге задачу с открытым скоупом — типа "а давайте добавим в язык немножко нейросеток для проверки текста документа на юридическую корректность" или "вот тут один из клиентов попросил добавить в язык паттерн-матчинг и иммутабельность".

А вот для "формул над строками" тащить в проект бомбу? Я вас умоляю.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[14]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 22.11.21 12:04
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Например, как вы гарантируете, что питоновый однострочник не зацикливается? Будете запускать питон-машину с таймаутом? Или будете проблему останова решать для каждой формулы?

S>Или, скажем, что помешает "пользователю" втащить в свою формулу IO-пакеты, и испоганить окружение в сервере приложений, работая под привилегиями системного аккаунта?
про питон не знаю точно, но если импорты возможны только на уровне модуля. то мы можем обернуть выражение в функцию-пустышку.
в сишапр-скрипте тем более единицу компиляции можно проверить юзинги по черному списку.

вообщем, помните супер-бразуер от мс ?
даже с их мощностями не хватило вывезти с нуля.
для того и придумали повторное использование. разве нет?
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[18]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 23.11.21 03:38
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Статические референсы — не единственный способ загрузки сборок.

Согласен, способов много, отсюда и гибкость платформы. Выстрелить в ногу можно.
Интересно, вот тут например, как можно выполнить произвольный код?

using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Scripting;

var options = Microsoft.CodeAnalysis.Scripting.ScriptOptions
.Default.WithImports(Array.Empty<string>())
.WithReferences(Array.Empty<MetadataReference>());

var deleg = await CSharpScript.EvaluateAsync<Func<string, string, string>>("(a, b) => a + b", options);
Console.WriteLine(deleg("Hello, ", "Alice!"));
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[19]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 23.11.21 05:37
Оценка:
Здравствуйте, vaa, Вы писали:

vaa>Здравствуйте, Ночной Смотрящий, Вы писали:


НС>>Статические референсы — не единственный способ загрузки сборок.

vaa>Согласен, способов много, отсюда и гибкость платформы. Выстрелить в ногу можно.
vaa>Интересно, вот тут например, как можно выполнить произвольный код?

https://dotnetfiddle.net/vPumI1

Пояснения нужны?
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Отредактировано 23.11.2021 5:40 Sinclair . Предыдущая версия .
Re[22]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 23.11.21 07:26
Оценка:
Здравствуйте, Sinclair, Вы писали:


S>Ок, вижу, что рассуждения по индукции — не ваша сильная сторона.


Ну что же, можно сделать вывод, что рефлексия это сильная сторона дотнета
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 23.11.21 09:16
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>Для несложных выражений проще взять чтото более мирное, обычные parser combinators например.


Пратт проще.

I>Я бы вообще начал с польской записи, это уровень студента-первокурсника.


Оно только для целей обучения и годно. Ну и парсер Пратта аналогичен по сложности обратной записи, это, собственно, одна из разновидностей operator precedence parser.

I>В любом случае сначала надо будет построить хоть какуюто грамматику.


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

I> Ошибки в этой части дадут месяцы и годы багфикса.


Я тебя умоляю. Негде там багфиксить столько, там кода будет на пару экранов.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[8]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 23.11.21 10:50
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

I>>Для несложных выражений проще взять чтото более мирное, обычные parser combinators например.


НС>Пратт проще.


В каких единицах мерить эту простоту?
parser combinator это обычно тривиальная библиотечка, доступная в готовом виде, что не требует покрытия сотнями юнит-тестов.
Код в таком виде выглядит примерно как грамматика, только немного дополнительного синтаксиса.
Самая сложная часть это 1 грамматика 2 вычисление-интерпретация.

I>>Я бы вообще начал с польской записи, это уровень студента-первокурсника.


НС>Оно только для целей обучения и годно. Ну и парсер Пратта аналогичен по сложности обратной записи, это, собственно, одна из разновидностей operator precedence parser.


Не понятно, откуда следует "аналогичен по сложности". У польской записи тривиальная вычислительная модель, которая очевидна даже человеку, не имеющему опыта в программировании. Потому её и применяют для обучения программированию.
Вот на счет Пратта — я ни разу вот не видел, чтоб бы в вузах начинали курс с этого алгоритма.

I>> Ошибки в этой части дадут месяцы и годы багфикса.


НС>Я тебя умоляю. Негде там багфиксить столько, там кода будет на пару экранов.


Элементарно "а давайте немного изменим язык" дает тебе переписывание. Нет внятной грамматики == хаос.
В каком виде ты собираешься держать спецификацию? Ну вот девелопер новый, хочет понять ваш язык. Ему что, в уме интерпретировать твой парсер что бы понять все возможные комбинации синтаксиса?
Re[9]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 23.11.21 13:36
Оценка:
Здравствуйте, Ikemefula, Вы писали:

I>parser combinator это обычно тривиальная библиотечка, доступная в готовом виде,


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

I> что не требует покрытия сотнями юнит-тестов.


Покрытие юнит-тестами парсера требуется в любом случае, даже при использовании готовых библиотек. Потому что от ошибок в грамматике и в построителе АСТ тебя они не застрахуют.

I>Код в таком виде выглядит примерно как грамматика


Еще раз, прочти внимательно — BNF грамматика выражений с приоритетами — штука довольно нетривиальная. Прелесть Пратта в том, что ему не нужна грамматика, ему достаточно простого списка операторов с приоритетами. Вот прям константно объявляешь static readonly _operators = new[] {new Op("+", BuildAdd), ...}, вот тебе и вся грамматика.
А для твоего комбинатора одно только BNF описание грамматики выражений с приоритетами и скобками потребует нехилого CS бекграунда. И что то мне подсказывает, что для ТС это практически show stopper.

I>Не понятно, откуда следует "аналогичен по сложности".


Это следует из того, что принцип, на котором они оба построены, примерно тот же.

I>Вот на счет Пратта — я ни разу вот не видел, чтоб бы в вузах начинали курс с этого алгоритма.


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

НС>>Я тебя умоляю. Негде там багфиксить столько, там кода будет на пару экранов.

I>Элементарно "а давайте немного изменим язык" дает тебе переписывание.

Нет, не дает. Если добавить оператор — просто добавляется константа в список (допил АСТ оставляем за скобками, он от типа парсера не зависит).

I>В каком виде ты собираешься держать спецификацию?


Попробуй читать что я пишу. В виде константного списка операторов.

I> Ну вот девелопер новый, хочет понять ваш язык. Ему что, в уме интерпретировать твой парсер что бы понять все возможные комбинации синтаксиса?


Вот честно, попробуй потратить пару часов своего времени и реализовать такой парсер. Оно и увлекательно, и полезно для самообразования, и все твои вопросы тут же отпадут.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[10]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 23.11.21 14:10
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

I>>parser combinator это обычно тривиальная библиотечка, доступная в готовом виде,


НС>Ну попробуй реализовать в ней парсинг выражений с приоритетами, а потом сравни с парой страничек Пратта, и все вопросы про единицы отпадут сами собой.


Я уже попробовал, и нахожу рекурсив-децент и парсеры комбинаторов проще чем этот пратт.

I>> что не требует покрытия сотнями юнит-тестов.


НС>Покрытие юнит-тестами парсера требуется в любом случае, даже при использовании готовых библиотек. Потому что от ошибок в грамматике и в построителе АСТ тебя они не застрахуют.


Меня интересует не сам факт наличия тестов, а их количество. Для кода "с нуля" этих тестов на порядки больше, чем для конкретной библиотеки.

НС>Еще раз, прочти внимательно — BNF грамматика выражений с приоритетами — штука довольно нетривиальная. Прелесть Пратта в том, что ему не нужна грамматика, ему достаточно простого списка операторов с приоритетами. Вот прям константно объявляешь static readonly _operators = new[] {new Op("+", BuildAdd), ...}, вот тебе и вся грамматика.


Нету потребности в сверлах, есть потребность в отверстиях. Поделись, как ты без грамматики собираешься поддерживать ну скажем iso-8601? Чем здесь поможет парсер пратта?
А дальше надо прикрутить валидацию поля c типом duration на фронте и там надо бы регэксп слепить и мейнтейнить его в т.ч. на клиенте, т.к. там оффлайн мод в наличии.
Вот и выходит, тебе всё равно надо иметь ту самую грамматику, на основе которой ты сможешь рендерить и правила парсинга, и правила валидации.
Т.е. в любом случае нужна грамматика и нужен приоритет операторов.
Внезапно, если глянуть протокол odata, всё так и есть — abnf + приоритет операторов. Имплементируй как хошь.
Правило для duration задано явно и безо всякого колупания в коде понятно, что там к чему.

НС>А для твоего комбинатора одно только BNF описание грамматики выражений с приоритетами и скобками потребует нехилого CS бекграунда. И что то мне подсказывает, что для ТС это практически show stopper.


Этот "нехилый бекграунд" дается на втором курсе, от силы — третьем.
А альтернатива какая? Каким чудом новому девелоперу понять, что вообще можно ждать от вашего парсера?

I>>Не понятно, откуда следует "аналогичен по сложности".

НС>Это следует из того, что принцип, на котором они оба построены, примерно тот же.

Непонятно. Есть А и Б. Каким образом используя формулу "принцип примерно тот же" понять, что сложнее, А или Б?

I>>Элементарно "а давайте немного изменим язык" дает тебе переписывание.

НС>Нет, не дает. Если добавить оператор — просто добавляется константа в список (допил АСТ оставляем за скобками, он от типа парсера не зависит).

Почему ты решил, что речь только про операторы? Если у тебя язык жестко не задан в самом начале, то это значит надо менять по ходу "а давайте всё будет не так"

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


Ты просто в другой форме повторяешь "там всё просто". Если у тебя других объяснений нет, то так и пиши: "там всё просто".
Re[11]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 23.11.21 14:22
Оценка:
Здравствуйте, Ikemefula, Вы писали:

НС>>Ну попробуй реализовать в ней парсинг выражений с приоритетами, а потом сравни с парой страничек Пратта, и все вопросы про единицы отпадут сами собой.

I>Я уже попробовал, и нахожу рекурсив-децент и парсеры комбинаторов проще чем этот пратт.

Ты точно пробовал реализовать Пратта? Потому что из топика у меня сложилось ощущение, что ты вообще не представляешь что это.

НС>>Покрытие юнит-тестами парсера требуется в любом случае, даже при использовании готовых библиотек. Потому что от ошибок в грамматике и в построителе АСТ тебя они не застрахуют.

I>Меня интересует не сам факт наличия тестов, а их количество.

Идентично. Вне зависимости от того как написан парсер. Надо покрыть все возможные конструкции в любом случае.

I>Нету потребности в сверлах, есть потребность в отверстиях. Поделись, как ты без грамматики собираешься поддерживать ну скажем iso-8601?


iso-8601 это вообще лексер, при чем тут парсинг? Обычный ДКА по классике вполне справляется. Тут бы я точно велосипеды изобретать не стал, включая построение таких вещей на комбинаторных парсерах.

I>Внезапно, если глянуть протокол odata, всё так и есть — abnf + приоритет операторов.


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

НС>>А для твоего комбинатора одно только BNF описание грамматики выражений с приоритетами и скобками потребует нехилого CS бекграунда. И что то мне подсказывает, что для ТС это практически show stopper.

I>Этот "нехилый бекграунд" дается на втором курсе, от силы — третьем.

Это если этот самый второй курс есть. У тебя вот он есть?

I>>>Не понятно, откуда следует "аналогичен по сложности".

НС>>Это следует из того, что принцип, на котором они оба построены, примерно тот же.
I>Непонятно.

Потому что ты не потрудился ознакомится с Праттом.

I>>>Элементарно "а давайте немного изменим язык" дает тебе переписывание.

НС>>Нет, не дает. Если добавить оператор — просто добавляется константа в список (допил АСТ оставляем за скобками, он от типа парсера не зависит).
I>Почему ты решил, что речь только про операторы?

Потому что ТС требуются просто несложные выражения, а не полноценные языки.

I>Если у тебя язык жестко не задан в самом начале, то это значит надо менять по ходу "а давайте всё будет не так"


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

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

I>Ты просто в другой форме повторяешь "там всё просто".

Потому что там на самом деле все просто. Ты попробуй.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[13]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 23.11.21 17:17
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Маинтейнить такой парсер будет в разы легче, чем рукопашную реализацию. Правил нам потребуется совсем-совсем немного, т.к. операций со строками очень конечное количество.


Еще раз. Не надо путать задачу написания парсера более менее развитой грамматики и парсер выражений. В первом случае я первый бы предложил генератор или библиотечку комбинатора. Более того, для второго случая тоже вполне можно использовать готовый генератор лексеров, если уж совсем лениво токены выпарсивать или нужен максимальный перф.
А вот для парсинга выше лексем во втором случае есть специализированный неуниверсальный алгоритм, реализация которого проще, чем написание грамматики для выражений с приоритетами, не говоря уж о заталкивании ее в реальный генератор со всеми его тараканами. Ну просто потому что эти выражения с приоритетами описываются в BNF на редкость извратно.
И с Праттом почему то у генераторов не очень, 99% используют ДКА для лексера и LR или LL для того что выше. Исключение составляет тот парсер что я 5 лет назад писал на предыдущей работе и, вроде бы, Nitra. С другой стороны, для Пратта генератор и не нужен особо, он там интересен только как часть полноценного LL или LR генератора, в которой есть специальный хардкод именно для выражений.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[15]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 24.11.21 09:27
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Эмм. А что там особенно извратного?


Запутанно, объемно и неочевидно.

S> Пишется всё примерно так же, как и слышится. Стоит один раз увидеть реализацию, как всё становится предельно очевидно. По одной продукции на приоритет:

S>
S>expr = add
S>add = mul '+' mul | mul '-' mul | mul 
S>mul = power '*' power | power '/' power | power '%' power | power
S>power = atom '^' atom | atom
S>atom = number | var | '-' atom | '(' expr ')'
S>number = [0-9]+
S>var = [a-zA-Z][a-zA-Z0-9]*
S>


Ну и сравни это просто со списком операторов в порядке приоритета.

S>Так нам же нужны ехать, а не шашечки. PEG парсеры не нуждаются в лексерах


Ну как не нуждаются. Граница лексер/парсер не нечто фундаментальное и жестко фиксированное. Ты можешь без лексера сделать и классический LL парсер. Отдельный лексер делается потому что даже со всеми оптимизациями типа пакрета PEG без лексера все равно заведомо медленее классического минимизированного ДКА. Поэтому, на практике, пока мы укладываемся в регулярку с LA, лучше использовать для парсинга именно его. А вот что уже в регулярку не лезет — тут можно поиграться с вариантами.

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


Для однострочных выражений Пратт интересен прежде всего своей простотой. Алгоритм — тривиальней не придумаешь, конфигурируется самым простым способом, какой вообще в принципе существует. Оверхед по переписыванию потом, если вдруг, его на тот же PEG минимален.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[16]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.11.21 11:26
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

S>> Пишется всё примерно так же, как и слышится. Стоит один раз увидеть реализацию, как всё становится предельно очевидно. По одной продукции на приоритет:

S>>
S>>expr = add
S>>add = mul '+' mul | mul '-' mul | mul 
S>>mul = power '*' power | power '/' power | power '%' power | power
S>>power = atom '^' atom | atom
S>>atom = number | var | '-' atom | '(' expr ')'
S>>number = [0-9]+
S>>var = [a-zA-Z][a-zA-Z0-9]*
S>>


НС>Ну и сравни это просто со списком операторов в порядке приоритета.


Получится строчек двести-триста кода вида op('^', 50).led(function (left) { равестистый код }) + вспомогательные функции, которые тоже нужно будет понять.

+ всё равно нужно описать лексер, вот эта часть в более-менее взрослом дсл будет конской.
Отредактировано 24.11.2021 11:30 Pauel . Предыдущая версия .
Re[16]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 24.11.21 13:04
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Ну и сравни это просто со списком операторов в порядке приоритета.

Эмм, пока у нас нет готовой библиотеки, которая умеет Пратт, принимая в качестве параметра список операторов в порядке приоритета, придётся посчитать не только сам список, но и под Пратта.
Ну, и чисто академический вопрос — как Пратт обрабатывает унарные операторы? Особенно если оператор совпадает по лексеме с бинарным оператором?

S>>Так нам же нужны ехать, а не шашечки. PEG парсеры не нуждаются в лексерах


НС>Ну как не нуждаются. Граница лексер/парсер не нечто фундаментальное и жестко фиксированное.

Так и не нуждаются. Обычно PEG парсеры едут прямо по потоку символов.
НС>Ты можешь без лексера сделать и классический LL парсер. Отдельный лексер делается потому что даже со всеми оптимизациями типа пакрета PEG без лексера все равно заведомо медленее классического минимизированного ДКА.
Производительность не мерил, спорить не возьмусь. Но, повторюсь, в данной задаче у нас явно на первом месте понятность грамматики и надёжность реализации.
S>>Наверное, по быстродействию Пратт выиграет, но для однострочных выражений нам это скорее всего будет неважно.
НС>Для однострочных выражений Пратт интересен прежде всего своей простотой. Алгоритм — тривиальней не придумаешь, конфигурируется самым простым способом, какой вообще в принципе существует. Оверхед по переписыванию потом, если вдруг, его на тот же PEG минимален.

Давайте может всё же сделаем забег? Решим задачу ТС при помощи Пратта и при помоши Pegasus — посмотрим, что будет лучше.
Предлагаю простейший набор:
1. Параметры ("переменные") только строковые
2. Операторы (в порядке возрастания приоритета):
boolean ? string : string -> string: тернарный оператор

boolean | boolean -> boolean,
boolean & boolean -> boolean,
!boolean -> boolean: логика

string > string -> boolean,
string < string -> boolean,
string >= string -> boolean,
string >= string -> boolean: лексикографические сравнения
string = string -> boolean: равенство
string != string -> boolean: неравенство
string ~= string -> boolean: оператор "начинается с"
string =~ string -> boolean: оператор "заканчивается на"
string ~ string -> boolean: оператор "содержит"
string + string -> string: конкатенация
string[int..int] -> string: оператор "подстрока"


int + int -> int,
int — int -> int,
int * int -> int,
int / int -> int: арифметика


3. Функции:
Len(string) -> int
Upper(string) -> string
Lower(string) -> string
Find(string, string) -> int
Replace(string, string, string) -> string
String(int) -> string

Вот я хорошо себе представляю, как бы я это разбирал PEG-парсером. А вот вручную, хоть Праттом, хоть LL, я бы не взялся.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[15]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.11.21 13:06
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Эмм. А что там особенно извратного? Пишется всё примерно так же, как и слышится. Стоит один раз увидеть реализацию, как всё становится предельно очевидно. По одной продукции на приоритет:

S>
S>expr = add
S>add = mul '+' mul | mul '-' mul | mul 
S>mul = power '*' power | power '/' power | power '%' power | power
S>power = atom '^' atom | atom
S>atom = number | var | '-' atom | '(' expr ')'
S>number = [0-9]+
S>var = [a-zA-Z][a-zA-Z0-9]*
S>

S>Всё. Вот вам выражения с тремя четырьмя приоритетами, 7 операторов. Хотите, чтобы я дописал семантические действия? И сравним, что проще — Пратт или PEG.

А ты не мог бы выдать этот пег для сравнения?

Накидал recursive descent парсер, только мне пришлось изменить немного грамматику, а то у меня не хотело есть например 2+2+2+2+2. Не уверен, насколько это эквивалентно твоей

/*
expr = add
add = mul (('+'|'-') mul)* 
mul = power (('*'|'/'|'%') power)*
power = atom ('^' atom)*
atom = number | var | '-' atom | '(' expr ')'
number = [0-9]+
var = [a-zA-Z][a-zA-Z0-9]*
*/

const digit = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
const letterLower = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'];
const letterUpper = letterLower.map(x => x.toUpperCase());
const letter = [...letterLower, ...letterUpper];
const letterOrDigit = [...letter, ...digit];

function parse(source) {
    let currentPosition = 0;

    function next(...tokens) {
        const t = peek(...tokens);

        if (t != null) {
            currentPosition += t.length;
            return t;
        }

        return null;
    }

    function peek(...tokens) {
        for (const t of tokens) {
            if (source.startsWith(t, currentPosition)) {
                return t;
            }
        }
        return null;
    }

    function revert(toPosition) {
        currentPosition = toPosition;
    }

    function expr() {
        return add();
    }

    function add() {
        const savePosition = currentPosition;
        let left = mul();

        while (true) {
            let operator = next('+', '-');
            if (operator == null) {
                break;
            }
            const right = mul();
            if (right == null) {
                revert(savePosition);
                return null;
            }
            left = {type: 'add', operator, left, right};
        }

        return left;
    }

    function mul() {
        const savePosition = currentPosition;
        let left = power();

        while (true) {
            let operator = next('*', '/', '%');
            if (operator == null) {
                break;
            }
            const right = power();
            if (right == null) {
                revert(savePosition);
                return null;
            }
            left = {type: 'mul', operator, left, right};
        }

        return left;
    }

    function power() {
        const savePosition = currentPosition;
        let left = atom();

        while (true) {
            let operator = next('^');
            if (operator == null) {
                break;
            }
            const right = atom();
            if (right == null) {
                revert(savePosition);
                return null;
            }
            left = {type: 'power', operator, left, right};
        }

        return left;
    }

    function atom() {
        return number() || variable() || negation() || grouping();
    }

    function grouping() {
        const savePosition = currentPosition;

        if (peek('(') == null) {
            return null;
        }
        next('(');
        const e = expr();
        if (e == null) {
            revert(savePosition);
            return null;
        }
        if (next(')') == null) {
            revert(savePosition);
        }
        return e;
    }

    function negation() {
        if (peek('-')) {
            next('-');

            const right = atom();

            return {type: 'negation', right};
        }

        return null;
    }

    function variable() {
        const input = [];

        const start = next(...letter);

        if (start == null) {
            return null;
        }

        input.push(start);

        while (true) {
            const x = next(...letterOrDigit);

            if (x == null) {
                break;
            }

            input.push(x);
        }

        return input.length === 0 ? null : {type: 'variable', name: input.join('')};
    }

    function number() {
        const input = [];

        while (true) {
            const d = next(...digit);

            if (d == null) {
                break;
            }

            input.push(d);
        }

        return input.length === 0 ? null : {type: 'number', value: input.join('')};
    }

    return expr();
}

console.log(JSON.stringify(parse(process.argv[2]), null, 4));
Отредактировано 24.11.2021 13:16 Pauel . Предыдущая версия . Еще …
Отредактировано 24.11.2021 13:11 Pauel . Предыдущая версия .
Re[17]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.11.21 13:15
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Давайте может всё же сделаем забег? Решим задачу ТС при помощи Пратта и при помоши Pegasus — посмотрим, что будет лучше.

S>Предлагаю простейший набор:

А может остановиться на твоей грамматике в 7 действий? Многовато работы выходит, по любому. Для сравнения алгоритмов должно хватить.
Re[17]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 24.11.21 14:50
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ну, и чисто академический вопрос — как Пратт обрабатывает унарные операторы? Особенно если оператор совпадает по лексеме с бинарным оператором?

примерно вот так
var prefix = function (id, nud) {
    var s = symbol(id);
    s.nud = nud || function () {
        scope.reserve(this);
        this.first = expression(70);
        this.arity = "unary";
        return this;
    };
    return s;
}
prefix("-");
prefix("!");
prefix("typeod");
prefix("(", function () {
    var e = expression(0);
    advance(")");
    return e;
});


nud это функция для обработки литералов, переменных и префиксных операторов.

Вот ядро алгоритма:
var expression = function (rbp) {
    var left;
    var t = token;
    advance();
    left = t.nud();           // обрабатывается префикс оператор
    while (rbp < token.lbp) {
        t = token;
        advance();
        left = t.led(left);   // инфиксные и суффиксные операторы
    }
    return left;
}


https://www.crockford.com/javascript/tdop/tdop.html
Re[18]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 24.11.21 16:07
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:
НС>https://github.com/atifaziz/Gratt
НС>Там 400 строк с огромными комментариями и пустотами, причем непосредственно алгоритм в сумме ну может строк 60. Камон, может мы еще и какой нибудь поиск подстроки в строке будем отдельной либой тянуть, в JS такое любят?
Простите, но где именно там 400 строк?
Я вот вижу, что простейшая арифметика занимает 500 строк.

НС>Сравни с любой реализацией PEG на выбор.

Ну, сравнил. https://github.com/evilguest/StringExpressionParser/blob/master/StringExpressionParser/Arithmetics.peg
НС>Вы просто почему то упорно считаете что Пратт это такой навороченный рокетсайнс типа какого нибудь GLL, PEG или комбинатора, и воспринимаете мои слова как будто я предлагаю этих монстров руками писать. В то время как Пратт это полный примитив, стократ проще не только вышепреречисленных, но и даже банальных регексов. Сложность, реально, уровня поиска подстроки или преобразования числа в строку.
Вопрос не в примитивности, а в затратах на реализацию.

НС>Не сочти за невежливость, но тут тебе придется воспользоваться гуглом и прочесть про алгоритм.

ок, посмотрел. Ну, норм.

НС>Когда плевать на перф — да. А когда не плевать — появляются вполне честные лексеры с регулярками.

Ну, до перфа мы ещё доберёмся.

НС>И поэтому куча рекурсивных правил проще простого сортированного списка операторов? Ну ОК, я тебя понял.

Ну зачем вы хитрите? "Простой сортированный список операторов" приходится снабжать ещё и функциями разбора

НС>Не, столько времени я не готов на этот спор тратить, сорри.

Ну, нет так нет. Просто если бы было достаточно "простого сортированного списка операторов", то написание парсера заняло бы примерно столько же времени, сколько написание вашего поста.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 24.11.21 17:40
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Простите, но где именно там 400 строк?

S>Я вот вижу, что простейшая арифметика занимает 500 строк.

Ну что за шулерство? Там АСТ, размер которого не зависит от типа парсера. Сам парсер не в тестах, а в файле Parser.cs.

НС>>Не, столько времени я не готов на этот спор тратить, сорри.

S>Ну, нет так нет. Просто если бы было достаточно "простого сортированного списка операторов", то написание парсера заняло бы примерно столько же времени, сколько написание вашего поста.

Нет.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 25.11.21 02:29
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Здравствуйте, Ночной Смотрящий, Вы писали:


НС>>Тогда проще всего ознакомиться с алгоритмом Пратта и накидать нужный движочек за пару часов с нуля. Если время работы важнее времени старта — накинь еще пару часиков на реализацию простенького компилятора. В любом случае, за рабочий день, максимум два справишься.


S>В наше время уже так не делают. Есть nuget, есть sof. Все что сверх того — то от лукавого.

Вот нашел код на питоне, правда не понял, как аргументы подавать на вход. правда больше понравилось "метод Пратта", а не "алгоритм".

operators = { # приоритеты и функции led
    '+': [1, lambda left: "(%s + %s)" % (left, parse(1))],
    '*': [2, lambda left: "(%s * %s)" % (left, parse(2))],
    '^': [3, lambda left: "(%s ^ %s)" % (left, parse(3))],
    '$': [0]
    }

def lbp(t):
    try:
        return operators[t][0]
    except KeyError:
        return 0
    
def nud(t):
    return t

def led(t,left):
    return operators[t][1](left)

# можно соорудить класс для каждого оператора, но это очень больше строчек получится.

def parse(rbp=0):
    global tokens
    tok = tokens.pop(0)
    result = nud(tok)
    while lbp(tokens[0]) > rbp:
        tok = tokens.pop(0)
        result = led(tok,result)
    return result

def evaluate(expr):
    global tokens
    tokens = expr.split(" ") + ['$']
    return parse()

x = evaluate("1 + 2 * 3 ^ 4 * 5 + 6")
print(x)
# https://habr.com/ru/post/50349/
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 25.11.21 02:37
Оценка:
Здравствуйте, Shmj, Вы писали:

S>Кто что посоветует.


https://dzone.com/articles/parsing-in-c-all-the-tools-and-libraries-you-can-u-2
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[3]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.11.21 07:33
Оценка:
Здравствуйте, RonWilson, Вы писали:

RW>Можно же куда проще: COM с IActiveScript, а там VBScript


При всей несуразности это довольно удачный движок для автоматизации приложений. В нулевых подобные движки были нормой в больших десктопных приложениях. Юзер мышом прокликал нужный ему функционал, получил запись скрипта, потом в редакторе добавил тут и там параметров, добавил своих обработчиков и получил цельный плагин который решает его задачу.
Т.е. буквально за час-два юзер без серьезного CS бекграунда может накидать своё решение и получит внятный модуль для распространения.
Re[4]: Простой скрипт внутри приложения (в виде строки)
От: RonWilson Россия  
Дата: 25.11.21 07:52
Оценка:
Здравствуйте, Ikemefula, Вы писали:

RW>>Можно же куда проще: COM с IActiveScript, а там VBScript


I>При всей несуразности это довольно удачный движок для автоматизации приложений.


Ну а почему нет, быстро и просто, уж точно пошустрее будет многих предложенных тут, а тащить фактически с собой ничего не нужно
Re[5]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 25.11.21 08:17
Оценка:
Здравствуйте, RonWilson, Вы писали:


RW>Ну а почему нет, быстро и просто, уж точно пошустрее будет многих предложенных тут, а тащить фактически с собой ничего не нужно

точно пошустрее? сомневаюсь я.
вопросы безопасности всплывут опять же.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[5]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 25.11.21 08:18
Оценка:
Здравствуйте, RonWilson, Вы писали:

I>>При всей несуразности это довольно удачный движок для автоматизации приложений.


RW>Ну а почему нет, быстро и просто, уж точно пошустрее будет многих предложенных тут, а тащить фактически с собой ничего не нужно


Тогда это было мегапопулярно. Сейчас тот класс приложений вымер. Запилить аналог для веба это мягко говоря нетривиальная задача. на фронте это не нужно, а на сервере тебе никто не даст такое выполнять, т.к. это в чистом виде дыра в безопасности.
Re[6]: Простой скрипт внутри приложения (в виде строки)
От: RonWilson Россия  
Дата: 25.11.21 08:21
Оценка:
Здравствуйте, vaa, Вы писали:

RW>>Ну а почему нет, быстро и просто, уж точно пошустрее будет многих предложенных тут, а тащить фактически с собой ничего не нужно

vaa>точно пошустрее? сомневаюсь я.

все же измерить можно, вроде как задача у ТС не что-то там особо сложное делато, то почему нет?

vaa>вопросы безопасности всплывут опять же.


они в любом случае всплывут, когда кто-то берет какую-то строчку из БД и выполняет ее, не?
Re[7]: Простой скрипт внутри приложения (в виде строки)
От: vaa  
Дата: 25.11.21 08:34
Оценка:
Здравствуйте, RonWilson, Вы писали:

RW>все же измерить можно, вроде как задача у ТС не что-то там особо сложное делато, то почему нет?

Вот и я о том же. Давно как-то измерял. Судя по скорости оно интерпретирует построчно. Ну то есть несоизмеримо дольше чем любой другой известный движок.

RW>они в любом случае всплывут, когда кто-то берет какую-то строчку из БД и выполняет ее, не?

VBS вообще изначально для администрирования системы был задуман. Собственный парсер дает вам отсутствие недокументированных возможностей.
А так то если система находится в ограниченном сегменте. База вынесена отдельно. приложение находится на выделенной виртуалке за проксей.
Ну типа, проблемы сетевого админа.
☭ ✊ В мире нет ничего, кроме движущейся материи.
Re[8]: Простой скрипт внутри приложения (в виде строки)
От: RonWilson Россия  
Дата: 25.11.21 08:45
Оценка:
Здравствуйте, vaa, Вы писали:

RW>>все же измерить можно, вроде как задача у ТС не что-то там особо сложное делато, то почему нет?

vaa>Вот и я о том же. Давно как-то измерял. Судя по скорости оно интерпретирует построчно. Ну то есть несоизмеримо дольше чем любой другой известный движок.

Вроде ТС и нужна одна строчка, я же не настаиваю на VBS, просто добавил в копилку, вдруг он скажет — "О! То что надо!! Всю жизнь мечтал о VBS"

RW>>они в любом случае всплывут, когда кто-то берет какую-то строчку из БД и выполняет ее, не?

vaa>VBS вообще изначально для администрирования системы был задуман. Собственный парсер дает вам отсутствие недокументированных возможностей.
vaa>А так то если система находится в ограниченном сегменте. База вынесена отдельно. приложение находится на выделенной виртуалке за проксей.
vaa>Ну типа, проблемы сетевого админа.

Проблемы негров админа шерифа не волнуют?)
Re[18]: Простой скрипт внутри приложения (в виде строки)
От: Sinclair Россия https://github.com/evilguest/
Дата: 26.11.21 09:49
Оценка:
I>Для сравнения алгоритмов должно хватить.

Вопрос открытый. На микропримерах есть риск не увидеть сложностей.

Я всё же закоммитил парсер строковых выражений, хоть и неполный. Но для прототипа сойдёт.
Положа руку на сердце, признаю: потратил больше времени, чем ожидал.

Не знаю, будет ли парсер, основанный на Пратте, более простым.

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

Ещё один неприятный побочный эффект — Pegasus недостаточно жадный. Если он успешно заматчил стартовое правило на префикс текста, то он успокаивается и возвращает неполный текст.
Так что выражение типа "а + b + " разбирается как Concat(a, b), а не приводит (как ожидается) к ошибке.
Например, Lingo от Area9 такого не позволяет, и наличие лишнего мусора после успеха стартового правила считается синтаксической ошибкой.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Re[19]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 26.11.21 12:37
Оценка:
Здравствуйте, Sinclair, Вы писали:

S>Ещё один неприятный побочный эффект — Pegasus недостаточно жадный. Если он успешно заматчил стартовое правило на префикс текста, то он успокаивается и возвращает неполный текст.

S>Так что выражение типа "а + b + " разбирается как Concat(a, b), а не приводит (как ожидается) к ошибке.

Ну вот мы и получаем последствия использования грамматик.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[20]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.11.21 15:36
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

S>>Так что выражение типа "а + b + " разбирается как Concat(a, b), а не приводит (как ожидается) к ошибке.


НС>Ну вот мы и получаем последствия использования грамматик.


У Пратта есть свои последствия, что очевиднл.

Например, если ты led неверно описал, будешь на некоторых выражениях получать хрень.
Re[21]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 26.11.21 15:43
Оценка:
Здравствуйте, Ikemefula, Вы писали:

НС>>Ну вот мы и получаем последствия использования грамматик.

I>У Пратта есть свои последствия, что очевиднл.
I>Например, если ты led неверно описал, будешь на некоторых выражениях получать хрень.

Банальная ошибка это одно, а вот неочевидное и трудно отлавливаемое поведение иза всяких спецэффектов про жадность и внутренние зависимости грамматики — совсем другое, особенно в плане потребной квалификации для поиска и фикса. У 90% программистов даже от самого термина "жадность" глаза будут квадратные.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[22]: Простой скрипт внутри приложения (в виде строки)
От: Ikemefula Беларусь http://blogs.rsdn.org/ikemefula
Дата: 26.11.21 19:31
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Банальная ошибка это одно, а вот неочевидное и трудно отлавливаемое поведение иза всяких спецэффектов про жадность и внутренние зависимости грамматики — совсем другое, особенно в плане потребной квалификации для поиска и фикса. У 90% программистов даже от самого термина "жадность" глаза будут квадратные.


В целом, ты потратил много больше времени на форум, нежели на тот простецкий парсер по методу Пратта.
Re[20]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 14.12.21 05:10
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

НС>Начни с книжки с драконом.


Можно ткнуть в книгу?
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.