Re[23]: Простой скрипт внутри приложения (в виде строки)
От: Ночной Смотрящий Россия  
Дата: 26.11.21 19:35
Оценка: -1
Здравствуйте, Ikemefula, Вы писали:

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


Ну не много больше, но сопопставимо, и?
На форуме я отвлекаюсь от работы, а не пытаюсь работать еще.
... << RSDN@Home 1.3.17 alpha 5 rev. 62>>
Re[23]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 26.11.21 20:40
Оценка: +1 -1
Здравствуйте, Ikemefula, Вы писали:

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


Дело не во времени а в мозговых ресурсах. Потратить время на расслабоне, просто удовлетворив свою потребность в общении — это не то же самое, что концентрированно что-то делать. После расслабона можно поработать — а вот когда потратил мозговые ресурсы — хрена с два.
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[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[20]: Простой скрипт внутри приложения (в виде строки)
От: Shmj Ниоткуда  
Дата: 14.12.21 05:10
Оценка:
Здравствуйте, Ночной Смотрящий, Вы писали:

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


Можно ткнуть в книгу?
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>>
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.