- PVSM.RU - https://www.pvsm.ru -
Всем привет.
В школьном и более продвинутом курсе информатики есть учебный язык - Кукарача [1]. Довольно удачный, для обучения детей программированию. Простой, понятный, визуальные результаты с первой строчки.
Авторы курса сделали только exe-шник под Windows. Когда младший сын начал требовать "Папа научи программировать" принял волевое решение - сделаю свою имплементацию. И сделал [2].
Есть прямоугольное поле. Жучок и буквочки. Нужно писать программы, что бы жучок правильным образом подвигал буковки.
Поддерживаются простые команды - ВВЕРХ
, ВНИЗ
, ВПРАВО
, ВЛЕВО
и их группировка с помощью {}
.
После каждого действия известен результат - какую букву толкнул жучок.
Есть циклы - ПОВТОРИ x
, ПОКА y
и условие ЕСЛИ z ТО ... ИНАЧЕ ...
И даже процедуры - ЭТО proc_name ... КОНЕЦ
Поэтому, в процессе обучения ребенок учится довольно сложных концепциям включая рекурсию и процедурное программирование.
Поле работает совсем очевидно - массивчик char'ов и специальный символ для жучка. Процедуры, которые передвигают жучка изменяя состояние. Запоминаем последнюю букву, которую толкнули. Осталось добавить загрузку/выгрузку в строку примерно такого вида:
А_А__
_1_1_
_____
____~
а также колбек на изменение, что бы отрисовывать и симпатичный компонент готов.
Оказалось, что сделать интерпретатор не так уж и сложно. Надо понимать что такое синтаксис и грамматика [3], почитать немного примеров и воспользоваться готовыми либами.
Я взял antlr [4] - т.к мой основной язык java и там этот генератор парсеров на слуху. В итоге получилась такая [5] грамматика
grammar Cockroach;
@header {
package ru.nizhikov.cockroach.antlr;
}
prog
: exprs EOF
;
exprs
: expr+
;
expr
: statement
| repeat
| while
| if
| proc
| id
| LINE_COMMENT
;
statement
: UP
| DOWN
| LEFT
| RIGHT
| STAY
| group
;
repeat
: REPEAT NUM expr
;
while
: WHILE condition expr
;
group
: OPEN_BRACKET exprs CLOSE_BRACKET
;
if
: IF condition THEN statement (ELSE statement)?
;
proc
: THIS id exprs END
;
condition
: NOT? id
| NOT? EMPTY
| NOT? NUMBER
;
id
: ID
;
LINE_COMMENT : '//' ~[nr]* -> skip;
UP: 'ВВЕРХ';
DOWN: 'ВНИЗ';
LEFT: 'ВЛЕВО';
RIGHT: 'ВПРАВО';
STAY: 'СТОЯТЬ';
NOT: 'НЕ';
EMPTY: 'ПУСТО';
NUMBER: 'ЦИФРА';
REPEAT: 'ПОВТОРИ';
WHILE: 'ПОКА';
CHAR: 'БУКВА';
OPEN_BRACKET: '{';
CLOSE_BRACKET: '}';
IF: 'ЕСЛИ';
THEN: 'ТО';
ELSE: 'ИНАЧЕ';
THIS: 'ЭТО';
END: 'КОНЕЦ';
ID: LETTER (LETTER | DIGIT)*;
LETTER: [a-zA-Zа-яА-Я];
NUM: DIGIT+;
DIGIT: [0-9];
SPACE: [ rnt]+ -> skip;
Грамматика задает правила для парсера что бы из текста сформировать синтаксическое дерево. Пример на картинке.
Интерпретатору всего-лишь надо обойти это дерево верным образом и выполнить необходимые действия. Действия следуют из их смысла:
Определение процедуры - запоминаем имя процедуры в специальной мапке. Ключ - название, значение - поддерево команд.
Вызов процедуры (токен ID) - ищем определение процедуры и вызываем соответствующее поддерево команд.
Цикл ПОВТОРИ x
- выполняем поддерево x
раз.
Цикл ПОКА у
- проверяем условие y
и выполняем поддерево пока оно выполняется.
ЕСЛИ z ТО ... ИНАЧЕ ...
- проверяем условие z
и выполняем то или иное поддерево.
Обычные команды - изменяем состояние поля.
Последний раз я делал UI еще во времена когда jquery и extjs были модными :), поэтому погуглив как сейчас делается интерфейс слегка ох^Wудивился обилию возможностей. В итоге собрал из туториала который первым заработал рабочее one page application и запилил с помощью того что знаю - bootstrap и jquery.
Очень хотелось сделать подсветку синтаксиса, а нагугленный компонент [6] поддерживал другой генератор парсеров. Нет проблем - записать грамматику [7] немного другим синтаксисом проще простого.
Несмотря на то, что в CodeMirror довольно подробная документация разобраться в API оказалось не так просто. Возможно, я отвык от уровня документирования js компонент. Но, в итоге, подсветка синтаксиса и текущей команды во время дебага и запуска работает.
Сохранение файликов сделал через localStorage - удобненько.
Первая реализация интерпретатора написана на java и работает через консоль. Пошаговое выполнение (отладку) легко сделать через ожидание ввода с консоли.
А вот в javascript простой возможности останавить выполнение в рандомном месте нет. Поэтому, пришлось заморочиться и сделать, что бы интерпретация приложения работала на promise'ах. Команда кукарачи выполняется при выполнении Promise.resolve
.
Вкратце - github прекрасен)
Оказалось, что в github есть бесплатный, автоматизированный, удобный функционал, что бы опубликовать one page application. Называется github pages [8]. Обалденно удобно. Собираешь свое приложение, указываешь папочку, жмешь кнопку и вуаля - приложение готово и работает [2].
Ну вот и все pet project готов и вроде как работает. Ребенок два раза позанимался программированием и получил массу удовольствия. Я тоже доволен и пописал интересный код.
Иходники - https://github.com/nizhikov/cockroach [9]
А еще у меня есть канал с выступлениями [10] и ссылками [11] на интересные пейперы из мира разработки СУБД.
Автор: Николай Ижиков
Источник [12]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/nenormal-noe-programmirovanie/379059
Ссылки в тексте:
[1] Кукарача: https://robotlandia.ru/abc4/0101.htm
[2] сделал: https://nizhikov.github.io/cockroach/
[3] синтаксис и грамматика: https://en.wikipedia.org/wiki/Syntax_(programming_languages)
[4] antlr: https://www.antlr.org/
[5] такая: https://github.com/nizhikov/cockroach/blob/master/console/src/main/antlr/Cockroach.g4
[6] компонент: https://codemirror.net/
[7] записать грамматику: https://github.com/nizhikov/cockroach/blob/master/cockroach-web/cockroach.grammar
[8] github pages: https://pages.github.com/
[9] https://github.com/nizhikov/cockroach: https://github.com/nizhikov/cockroach
[10] выступлениями: https://t.me/nizhikovTalks
[11] ссылками: https://t.me/db_links
[12] Источник: https://habr.com/ru/post/689050/?utm_source=habrahabr&utm_medium=rss&utm_campaign=689050
Нажмите здесь для печати.