Работаю над новой функциональностью для моего компилятора машин состояний — Guile-SMC.
Итоги работы: получилось сделать преобразование ДКА в код на Scheme, который никаким образом не зависит от самого Guile-SMC. На выходе получается самодостаточный код (который можно записать в одном файле), который похож на тот, который я мог бы написать руками.
Для того, чтобы получить подобный самодостаточный код, я копирую ядро Guile-SMC в выходной код, при этом сам ДКА преобразуется в подобное представление (реальный пример):
Из интересного: получилось также сделать некую "оптимизацию" выходного кода путём удаления неиспользуемых процедур.
Теперь у Guile-SMC три режима (цели) компиляции:
-
-
-
Пример запуска с указанием цели компиляции:
#projects #guile #smc #compiler
Итоги работы: получилось сделать преобразование ДКА в код на Scheme, который никаким образом не зависит от самого Guile-SMC. На выходе получается самодостаточный код (который можно записать в одном файле), который похож на тот, который я мог бы написать руками.
Для того, чтобы получить подобный самодостаточный код, я копирую ядро Guile-SMC в выходной код, при этом сам ДКА преобразуется в подобное представление (реальный пример):
(define (run-fsm context)
""
(define (DEFAULT context)
"Count parenthesis."
(let ((event (event-source context)))
(cond ((guard:eof-object? context event)
(let ((context (action:validate context event)))
(log-debug "[~a] -> [*]" 'DEFAULT)
context))
((guard:semicolon? context event)
(let ((context (action:no-op context event)))
(log-debug "[~a] -> [~a]" 'DEFAULT 'COMMENT)
(COMMENT context)))
((guard:double-quote? context event)
(let ((context (action:no-op context event)))
(log-debug "[~a] -> [~a]" 'DEFAULT 'STRING)
(STRING context)))
((#{guard:#t}# context event)
(let ((context (action:count context event)))
(DEFAULT context))))))
(define (STRING context)
"Skip a string."
(let ((event (event-source context)))
(cond ((guard:double-quote? context event)
(let ((context (action:no-op context event)))
(log-debug "[~a] -> [~a]" 'STRING 'DEFAULT)
(DEFAULT context)))
((#{guard:#t}# context event)
(let ((context (action:no-op context event)))
(STRING context))))))
(define (COMMENT context)
"Skip a comment."
(let ((event (event-source context)))
(cond ((guard:newline? context event)
(let ((context (action:no-op context event)))
(log-debug "[~a] -> [~a]" 'COMMENT 'DEFAULT)
(DEFAULT context)))
((#{guard:#t}# context event)
(let ((context (action:no-op context event)))
(COMMENT context))))))
(DEFAULT context))
Из интересного: получилось также сделать некую "оптимизацию" выходного кода путём удаления неиспользуемых процедур.
Теперь у Guile-SMC три режима (цели) компиляции:
-
guile
— обычный режим компиляции, который выбирается по-умолчанию. В этом случае выходной код зависит от наличия Guile-SMC в системе и без него выполняться не будет.-
guile-standalone-copy
— моя первая попытка сделать самодостаточный код. В этом случае все необходимые модули Guile-SMC копируются в отдельный каталог рядом с выходным ДКА, и зависимости ДКА переписываются так, чтобы они указывали на скопированные модули.-
guile-standalone
— вторая (текущая) попытка сделать самодостаточный код, и похоже самая успешная (хотя я решил оставить guile-standalone-copy
как вариант, т.к. в некотроых случаях он может быть удобнее.)Пример запуска с указанием цели компиляции:
$ cat fsm.puml | smc compile -L . -U "((context))" -t guile-standalone -m "(custom-fsm)" > custom-fsm.scm
#projects #guile #smc #compiler
GitHub
GitHub - artyom-poptsov/guile-smc: GNU Guile State Machine Compiler
GNU Guile State Machine Compiler. Contribute to artyom-poptsov/guile-smc development by creating an account on GitHub.
👍1