├── LICENSE ├── README.md └── assignments ├── NFA.js ├── State.js └── fragments ├── char.js └── epsilon.js /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Dmitry Soshnikov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Automata Theory. Building a RegExp machine 2 | 3 | This repo contains assignments for the [Automata Theory. Building a RegExp machine machine](https://www.youtube.com/playlist?list=PLGNbPb3dQJ_4YjExEWguwgd1iWUjWvybc) class, where we study Theory of Computation on the practical example of implementing a Regular Expressions machine. 4 | 5 | In the class you will learn: 6 | 7 | - RegExp history 8 | - Formal grammars: G = (N, T, P, S) 9 | - Regular grammars: Type 3 10 | - Finite automata FA = (Q, Σ, Δ, q0, F) 11 | - NFA, ε-NFA, DFA 12 | - Basic NFA fragments for RegExp 13 | - Single Character and Epsilon-machines 14 | - Concatenation pattern 15 | - Union pattern 16 | - Kleene-closure 17 | - Complex machines 18 | - Syntactic sugar 19 | - NFA optimizations 20 | - NFA acceptor 21 | - NFA table 22 | - DFA table 23 | - DFA minimization 24 | - RegExp match 25 | 26 | In addition, implementing a RegExp machine might be a non-trivial task, so building such a machine will definitely make you a better engineer, with transferable knowledge of different data structures and algorithms, which you'll be able to use in other parts of your career. 27 | 28 | ## Assignments 29 | 30 | Assignments are implemented in [Node.js](https://nodejs.org/en/). After installing, you can test and run e.g. as: 31 | 32 | ``` 33 | node assignments/State.js 34 | 35 | > All assertions passed! 36 | ``` 37 | 38 | - [FA State class](https://github.com/DmitrySoshnikov/at-regexp-machine/tree/master/assignments/State.js) 39 | - [Single character fragment](https://github.com/DmitrySoshnikov/at-regexp-machine/tree/master/assignments/fragments/char.js) 40 | - [Epsilon fragment](https://github.com/DmitrySoshnikov/at-regexp-machine/tree/master/assignments/fragments/epsilon.js) -------------------------------------------------------------------------------- /assignments/NFA.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Automata Theory. Building a RegExp machine. 3 | * 4 | * Video lecture: https://www.youtube.com/watch?v=_AK_ldfOQB0 5 | * 6 | * by Dmitry Soshnikov 7 | */ 8 | 9 | /** 10 | * NFA class. Encapsulates input and output states. 11 | * 12 | * The `test` function, which actually tests whether this 13 | * machine accepts a string or not, is just a thin 14 | * wrapper on top of the `test` method of the input state. 15 | */ 16 | class NFA { 17 | constructor(inState, outState) { 18 | this.inState = inState; 19 | this.outState = outState; 20 | } 21 | 22 | /** 23 | * Tests whether this NFA matches the 24 | * string. Delegates to the input state. 25 | */ 26 | test(string) { 27 | return this.inState.test(string); 28 | } 29 | } 30 | 31 | module.exports = NFA; -------------------------------------------------------------------------------- /assignments/State.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Automata Theory. Building a RegExp machine. 3 | * 4 | * Assignment 1: implement FA State class. 5 | * 6 | * Video lecture: https://www.youtube.com/watch?v=vGEbvqpNlbc 7 | * 8 | * by Dmitry Soshnikov 9 | */ 10 | 11 | // ----------------------------------------------------------------------------- 12 | 13 | /** 14 | * The State class represents a state in a finite automata. 15 | */ 16 | class State { 17 | constructor({accepting = false}) { 18 | /** 19 | * Whether this state accepting or not. 20 | */ 21 | this.accepting = accepting; 22 | 23 | /** 24 | * Transitions map: key is a transition symbol, 25 | * value - the Set of destination states for this symbol. 26 | */ 27 | this.transitionsMap = new Map(); 28 | } 29 | 30 | /** 31 | * Adds a transition for a symbol. 32 | */ 33 | addTransitionForSymbol(symbol, state) { 34 | // Implement here... 35 | } 36 | 37 | /** 38 | * Returns a list of destination states for this symbol. 39 | */ 40 | getTransitionsForSymbol(symbol) { 41 | // Implement here... 42 | } 43 | } 44 | 45 | // ----------------------------------------------------------------------------- 46 | // Test cases 47 | 48 | // Your assignment is to implement `addTransitionForSymbol` and 49 | // `getTransitionsForSymbol` methods above, and make sure all 50 | // assertions below pass. 51 | 52 | const assert = require('assert'); 53 | 54 | function runTests() { 55 | 56 | const s1 = new State({accepting: false}); 57 | const s2 = new State({accepting: true}); 58 | 59 | 60 | // Add transition on character 'a' from state 61 | // s1 to state s2: 62 | s1.addTransitionForSymbol('a', s2); 63 | 64 | const transitions = s1.getTransitionsForSymbol('a'); 65 | 66 | // There should be only one transition, to the state s2. 67 | assert.equal(transitions.size, 1); 68 | assert.equal(transitions.has(s2), true); 69 | } 70 | 71 | if (require.main === module) { 72 | runTests(); 73 | console.log('All assertions passed!'); 74 | } 75 | -------------------------------------------------------------------------------- /assignments/fragments/char.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Automata Theory. Building a RegExp machine. 3 | * 4 | * Assignment 2: implement Single character NFA fragment. 5 | * 6 | * Video lecture: https://www.youtube.com/watch?v=_AK_ldfOQB0 7 | * 8 | * by Dmitry Soshnikov 9 | */ 10 | 11 | const NFA = require('../NFA'); 12 | 13 | /** 14 | * Factory function for a single character NFA. 15 | */ 16 | function char(symbol) { 17 | // Implement here... 18 | } 19 | 20 | // ----------------------------------------------------------------------------- 21 | // Test cases 22 | 23 | // Your assignment is to implement `char` factory function, 24 | // and make sure all assertions below pass. 25 | 26 | const assert = require('assert'); 27 | 28 | function runTests() { 29 | const a = char('a'); 30 | 31 | assert.equal(a.inState.accepting, false); 32 | assert.equal(a.outState.accepting, true); 33 | 34 | const transition = a.getTransitionsForSymbol('a'); 35 | 36 | assert.equal(transitions.size, 1); 37 | assert.equal(transitions.has(a.outState), true); 38 | } 39 | 40 | if (require.main === module) { 41 | runTests(); 42 | console.log('All assertions passed!'); 43 | } 44 | 45 | module.exports = char; -------------------------------------------------------------------------------- /assignments/fragments/epsilon.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Automata Theory. Building a RegExp machine. 3 | * 4 | * Assignment 3: implement Epsilon NFA fragment. 5 | * 6 | * Video lecture: https://www.youtube.com/watch?v=_AK_ldfOQB0 7 | * 8 | * by Dmitry Soshnikov 9 | */ 10 | 11 | const NFA = require('../NFA'); 12 | 13 | /** 14 | * Factory function for a single character NFA. 15 | */ 16 | function epsilon(symbol) { 17 | // Implement here... 18 | } 19 | 20 | / ----------------------------------------------------------------------------- 21 | // Test cases 22 | 23 | // Your assignment is to implement `char` factory function, 24 | // and make sure all assertions below pass. 25 | 26 | const assert = require('assert'); 27 | 28 | function runTests() { 29 | const e = epsilon('a'); 30 | 31 | assert.equal(e.inState.accepting, false); 32 | assert.equal(e.outState.accepting, true); 33 | } 34 | 35 | if (require.main === module) { 36 | runTests(); 37 | console.log('All assertions passed!'); 38 | } 39 | 40 | module.exports = epsilon; --------------------------------------------------------------------------------