LOGOFALPROG Telegram 92
Подробности про командную строку
#код
Запилил на днях по работе командную строку с проверкой синтаксиса и автодополнением и похвастался этим в чатике. Народ проявил интерес и поэтому рассказываю подробнее.

Нужна эта штука для двух вещей. Во-первых, сценаристы, собирающие диалоги в редакторе, должны иметь возможность проверять доступность вариантов ответа (например, реплика возможна только при заданном уровне интеллекта или после выполнения квеста), а также вызывать скрипты при ответах. Во-вторых, для разработки нужна классическая игровая консоль для ввода читов и отладки. Чтобы разом покрыть оба этих юзкейса нужно написать нехитрый интерпретатор строки. Разумеется, он не будет поддерживать все фишки C#, а только некоторый базовый сабсет, вроде функций, операторов и скобочек.

Теперь о реализации. Несмотря на кажущуюся сложность задачи, имплементация у меня до боли простая и занимает чуть более тысячи строк. Первый элемент системы — это, конечно, лексический анализатор. Который у меня в коде какого-то фига называется Parser (надо не забыть переименовать в Lexer, а то чё я, как наркоман). Лексер представляет собой одну единственную функцию-генератор, которая в цикле читает символы строки и возвращает по одной токены лексем, которыми могут быть:
Value (строки, числа, true и false),
Identifier,
Dot,
Comma,
OpenBracket,
ClosedBracket,
Operator,
AssignmentOperator,
EndOfLine

Между лексемами могут быть пробелы, они игнорируются. Помимо типа, токен также хранит начало и длину фрагмента внутри входной строки (чтобы подсветить красным место, в котором произошла ошибка) и поле типа object для дополнительной информации: для value это считанное значение, для оператора — информация о том, какой конкретно оператор и т.п. Единственный нюанс, при чтении знака минус, нужно взглянуть на то, какой токен был перед этим: если значение, идентификатор или закрывающая скобка, то это оператор минус, в противном случае начало отрицательного числа.

Едем дальше. Непосредственно сам интерпретатор совмещённый с валидатором. Он у меня однопроходный, то есть я читаю очередь лексем слева направо и сразу же выполняю. Командная строка может выполнять только выражения. Выражение — это один или несколько операндов, разделённых операторами. Например,
a + b * c + d

или просто
a


Когда мы дошли до конца выражения (конец строки, запятая или закрывающая скобка), мы выполняем операторы в порядке их приоритета («схлопываем» по два операнда, пока не останется только один).

Операндом может выступать как значение, так и другое выражение в скобках. Поэтому если наткнёмся на открывающуюся скобку, то просто запускаем процесс парсинга вложенного выражения рекурсивно. И также операндом может выступать цепочка идентификаторов, типа такой:
Foo.bar.foo(a + b, c).foo.bar


В данном случае мы тоже выполняем всё последовательно. Сначала ищем объект среди глобальных. У меня разрешены только классы скриптов (считай, синглтоны) и enum’ы. Затем на каждый доступ через точку достаём через рефлекшн соответствующий member класса, а при вызове функции запускаем сперва вложенный парсинг выражений-аргументов через запятую.

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

Валидация происходит точно также, как и выполнение, только в «холостом» режиме: вместо честных вызовов функций и операторов, мы возвращаем объект-заглушку, которая знает какого типа должен быть результат. Этой информации достаточно, чтобы проверить весь синтаксис.

Автодополнение же сделано запуском валидации строки, в которую в определённом месте вставлен символ многоточие. При разборе
GlobalVars.Pl…

лексер вернёт не идентификатор «Pl», а специальную лексему типа Autocomplete «Pl...». Ну а синтаксический анализатор, если наткнётся на эту лексему там, где предполагается идентификатор, посмотрит, какие вообще есть варианты, и если что-то подходит, то бросит AutoCompleteException, содержащий остаток строки. Заменой выделенного текста на автодополненный вариант занимается уже гуишный контрол наверху.



tgoop.com/logofalprog/92
Create:
Last Update:

Подробности про командную строку
#код
Запилил на днях по работе командную строку с проверкой синтаксиса и автодополнением и похвастался этим в чатике. Народ проявил интерес и поэтому рассказываю подробнее.

Нужна эта штука для двух вещей. Во-первых, сценаристы, собирающие диалоги в редакторе, должны иметь возможность проверять доступность вариантов ответа (например, реплика возможна только при заданном уровне интеллекта или после выполнения квеста), а также вызывать скрипты при ответах. Во-вторых, для разработки нужна классическая игровая консоль для ввода читов и отладки. Чтобы разом покрыть оба этих юзкейса нужно написать нехитрый интерпретатор строки. Разумеется, он не будет поддерживать все фишки C#, а только некоторый базовый сабсет, вроде функций, операторов и скобочек.

Теперь о реализации. Несмотря на кажущуюся сложность задачи, имплементация у меня до боли простая и занимает чуть более тысячи строк. Первый элемент системы — это, конечно, лексический анализатор. Который у меня в коде какого-то фига называется Parser (надо не забыть переименовать в Lexer, а то чё я, как наркоман). Лексер представляет собой одну единственную функцию-генератор, которая в цикле читает символы строки и возвращает по одной токены лексем, которыми могут быть:

Value (строки, числа, true и false),
Identifier,
Dot,
Comma,
OpenBracket,
ClosedBracket,
Operator,
AssignmentOperator,
EndOfLine

Между лексемами могут быть пробелы, они игнорируются. Помимо типа, токен также хранит начало и длину фрагмента внутри входной строки (чтобы подсветить красным место, в котором произошла ошибка) и поле типа object для дополнительной информации: для value это считанное значение, для оператора — информация о том, какой конкретно оператор и т.п. Единственный нюанс, при чтении знака минус, нужно взглянуть на то, какой токен был перед этим: если значение, идентификатор или закрывающая скобка, то это оператор минус, в противном случае начало отрицательного числа.

Едем дальше. Непосредственно сам интерпретатор совмещённый с валидатором. Он у меня однопроходный, то есть я читаю очередь лексем слева направо и сразу же выполняю. Командная строка может выполнять только выражения. Выражение — это один или несколько операндов, разделённых операторами. Например,
a + b * c + d

или просто
a


Когда мы дошли до конца выражения (конец строки, запятая или закрывающая скобка), мы выполняем операторы в порядке их приоритета («схлопываем» по два операнда, пока не останется только один).

Операндом может выступать как значение, так и другое выражение в скобках. Поэтому если наткнёмся на открывающуюся скобку, то просто запускаем процесс парсинга вложенного выражения рекурсивно. И также операндом может выступать цепочка идентификаторов, типа такой:
Foo.bar.foo(a + b, c).foo.bar


В данном случае мы тоже выполняем всё последовательно. Сначала ищем объект среди глобальных. У меня разрешены только классы скриптов (считай, синглтоны) и enum’ы. Затем на каждый доступ через точку достаём через рефлекшн соответствующий member класса, а при вызове функции запускаем сперва вложенный парсинг выражений-аргументов через запятую.

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

Валидация происходит точно также, как и выполнение, только в «холостом» режиме: вместо честных вызовов функций и операторов, мы возвращаем объект-заглушку, которая знает какого типа должен быть результат. Этой информации достаточно, чтобы проверить весь синтаксис.

Автодополнение же сделано запуском валидации строки, в которую в определённом месте вставлен символ многоточие. При разборе
GlobalVars.Pl…

лексер вернёт не идентификатор «Pl», а специальную лексему типа Autocomplete «Pl...». Ну а синтаксический анализатор, если наткнётся на эту лексему там, где предполагается идентификатор, посмотрит, какие вообще есть варианты, и если что-то подходит, то бросит AutoCompleteException, содержащий остаток строки. Заменой выделенного текста на автодополненный вариант занимается уже гуишный контрол наверху.

BY Log of Alprog


Share with your friend now:
tgoop.com/logofalprog/92

View MORE
Open in Telegram


Telegram News

Date: |

“Hey degen, are you stressed? Just let it all out,” he wrote, along with a link to join the group. With Bitcoin down 30% in the past week, some crypto traders have taken to Telegram to “voice” their feelings. Telegram Android app: Open the chats list, click the menu icon and select “New Channel.” To view your bio, click the Menu icon and select “View channel info.”
from us


Telegram Log of Alprog
FROM American