https://github.com/buroni/automata-golf
A domain-specific language (DSL) for parsing regular, context-free and recursively enumerable languages.
https://github.com/buroni/automata-golf
context-free domain-specific-language dsl finite-state-machine fsm turing-machine
Last synced: about 1 year ago
JSON representation
A domain-specific language (DSL) for parsing regular, context-free and recursively enumerable languages.
- Host: GitHub
- URL: https://github.com/buroni/automata-golf
- Owner: Buroni
- License: mit
- Created: 2022-09-22T10:49:25.000Z (almost 4 years ago)
- Default Branch: main
- Last Pushed: 2023-05-22T19:27:28.000Z (about 3 years ago)
- Last Synced: 2025-03-27T01:22:39.138Z (over 1 year ago)
- Topics: context-free, domain-specific-language, dsl, finite-state-machine, fsm, turing-machine
- Language: JavaScript
- Homepage:
- Size: 183 KB
- Stars: 15
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# automata-golf
A domain-specific language (DSL) for parsing regular, context-free and recursively enumerable languages.
In `automata-golf`, a machine is defined by a series of path statements.
There's no need to explicitly define states or transitions.
The example below shows a machine with an initial state `s0`, which transitions
via `f` to and from the accepted state `s1` .

```
# 1,2, and 3 are all equivalent:
# 1
.s0 -f> (s1) -f> s0;
# 2
.s0 (s1);
# 3
s1 -f> .s0;
s0 t1;
```
## Stacking transitions
Multiple transitions from the same state can be stacked up:
```
.s0 -f> -g> -h> s1;
```
## Pushdown automata
`automata-golf` supports pushdown automota, i.e. a finite-state machine with
a stack and transitions that push/pop the stack.
The following transitions to `s1` on input `f` when `a` is top of the stack.
Upon the transition, it pushes `b` to the stack.
```
.s0 -f[a:b]> s1;
```

### Multiple stacks
2-stack PDAs are supported, making them equivalent to Turing machines. See the
example and corresponding automaton diagram below.
```
.s0 -f[a:b, _:c]> s1;
```

### Epsilon transitions
Epsilon is represented by `_`. For example the following transitions to `s1`
and pushes `$` to the second stack without consuming any input or popping either stack.
```
.s0 -_[_:_, _:$]> (s1);
# or equivalently:
.s0 -[_, :$]> (s1);
```
# Examples
## Regular languages
Regular languages can be captured using finite-state machines.
### Odd binary numbers
The following program accepts all binary numbers ending in `1`
```js
const { build } = require("./automata-golf/index.js");
const { machine } = build(`
.s0 -0> -1> s0 -1> (s1);
`);
machine.consume("10110").inAcceptState(); // false
machine.consume("1011").inAcceptState(); // true
```

### Self-driving robot
The following finite-state machine creates a robot that can be turned on and off,
and switches direction when it collides.
```js
const { build } = require("./automata-golf/index.js");
const { machine } = build(`
.off forward backward -push> off;
`);
machine.consume(["push", "collide"]).state; // backward
```
## Context-free languages
Pushdown automota are required to parse context-free languages.
### Odd-length palindromes
The following accepts all odd-length palindromes in the language `{a, b}`
```js
const { build } = require("automata-golf/index.js");
const { machine } = build(`
.s0 -[:$]> s1;
s1 -a[:a]> -b[:b]> s1;
s1 -a> -b> s2;
s2 -a[a]> -b[b]> s2;
s2 -[$]> (s3);
`);
machine.consume("abbba").inAcceptState(); // true
machine.consume("abb").inAcceptState(); // false
```
Note the program can be condensed to
```
.s0 -[:$]> s1 -a[_:a]> -b[:b]> s1 -a> -b> s2 -a[a]> -b[b]> s2 -[$]> (s3);
```

## Recursively enumerable languages
Recursively enumerable languages can be parsed by using a pushdown automaton with 2 stacks, equivalent to a Turing machine.
### anbncn
The following accepts input of the format anbncn:
```js
const { build } = require("automata-golf/index.js");
const machine = build(`
.s0 -a[:a]> s0 -_> s1 -b[a, :b]> s1 -_> s2 -c[_, b]> (s2);
`);
machine.consume("aabbcc").inAcceptState(); // true
machine.consume("abbc").inAcceptState(); // false
```

## Build to JS
The machine can be written to a JS file
```js
// A.js
const { build } = require("automata-golf/index.js");
build(".s0 -f> (s1)", { emitFile: "./machine.js" });
// B.js
const machine = require("./machine.js");
machine.consume("f");
```
### Target
Set `target` to `'browser'` to generate a machine that can be run in a browser
environment:
```js
build(".s0 -f> (s1)", { emitFile: "./machine.js", target: "browser" });
```