Commit eea788c2 authored by Yuanle Song's avatar Yuanle Song
Browse files

add a simple example of fsm in javascript

parent 1bff2513
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -109,6 +109,7 @@
      </div>
    </div>
    <script type="text/javascript" src="vendor/jquery.min.js"></script>
    <script type="text/javascript" src="fsm.js"></script>
    <script type="text/javascript">
      (function () {
	  /**
@@ -129,6 +130,16 @@

	  // page init
	  showDumbData();
	  console.assert(fsm.matchesSubstringAbb("123abb123") === true);
	  console.assert(fsm.matchesSubstringAbb("123ab123") === true);
	  console.assert(fsm.matchesSubstringAbb("123abaabb123") === true);
	  console.assert(fsm.matchesSubstringAbb("123abbb123") === true);
	  console.assert(fsm.matchesSubstringAbb("123ababab123") === false);
	  console.assert(fsm.matchesSubstringAbb("") === false);
	  console.assert(fsm.matchesSubstringAbb("123") === false);
	  console.assert(fsm.matchesSubstringAbb("123ab") === false);
	  console.assert(fsm.matchesSubstringAbb("123abb") === true);
	  console.assert(fsm.matchesSubstringAbb("abb") === true);

	  // setup event handler
	  $('.keyboard td').click(function (evt) {

fsm.js

0 → 100644
+76 −0
Original line number Diff line number Diff line
var fsm = function () {
    const debugging = false;

    const debug = function (msg) {
	if (debugging) {
	    console.log(msg);
	}
    };

    /**
     * a fsm that tries to match string "abb". see function
     * matchesSubstringAbb.
     */
    const matchAbbMachine = function () {
	this.stateWaitForA = "wait for a";
	this.stateWaitForFirstB = "wait for 1st b";
	this.stateWaitForSecondB = "wait for 2nd b";
	this.stateSucceed = "succeed";

	this.currentState = "wait for a";
	this.readch = function (ch) {
	    switch (this.currentState) {
	    case this.stateWaitForA:
		if (ch === 'a') {
		    this.currentState = this.stateWaitForFirstB;
		} else {
		    this.currentState = this.stateWaitForA;
		}
		break;
	    case this.stateWaitForFirstB:
		if (ch === 'b') {
		    this.currentState = this.stateWaitForSecondB;
		} else if (ch === 'a') {
		    // do nothing, keep current state.
		} else {
		    this.currentState = this.stateWaitForA;
		}
		break;
	    case this.stateWaitForSecondB:
		if (ch === 'b') {
		    this.currentState = this.stateSucceed;
		} else if (ch === 'a') {
		    this.currentState = this.stateWaitForFirstB;
		} else {
		    this.currentState = this.stateWaitForA;
		}
		break;
	    case this.succeed:
		// do nothing, keep current state.
		break;
	    }
	    debug("readch " + ch + ", currentState is " + this.currentState);
	    return this.currentState;
	};
    };

    /**
     * return true if given string has substring "abb" in it.
     * implemented using fsm.
     */
    const matchesSubstringAbb = function (str) {
	var machine = new matchAbbMachine();
	for (i = 0; i < str.length; ++i) {
	    machine.readch(str[i]);
	    if (machine.currentState === "succeed") {
		// console.log("matches");
		return true;
	    }
	}
	return false;
    };

    return {
	matchesSubstringAbb: matchesSubstringAbb
    };
}();
+45 −0
Original line number Diff line number Diff line
@@ -15,6 +15,36 @@ the parent DOM.

* current                                                             :entry:
** 
** 2017-01-26 design data structure for the calculator.
- this can be written and tested independently from the web UI.
- basic data:
  - stack of numbers.
  - current state and data in finite state machine (fsm).
  - data for undo. I think I can just take a snapshot of the fsm.

- how many states are there?

  init state is "waiting for number".

  | this state                   | event                     | next state                                       |
  |------------------------------+---------------------------+--------------------------------------------------|
  | waiting                      | press num keys or dot key | modify number, then waiting for number or action |
  | waiting for number or action | press num keys or dot key | modify number, then waiting for number or action |
  | waiting for number or action | press return key          | commit number, then waiting                      |
  | waiting for number or action | press +-*/                | commit number, do op, then waiting               |
  | waiting for number or action | press < key               | modify number, then waiting for number or action |

  There is no "ending state", the machine can always accept new keyboard events.

- a few display and error handling.

  - when number is "0", press more num0 will just show error and not modify the number.

  - when number is "", press dot will change number to "0."

  - when number already has a dot in it, future dot will just show error and
    not modify the number.

** 2017-01-26 make basic number input and arithmetic work
- DONE make event work.
  - TODO add some visual feedback when clicking a button. like in material design.
@@ -37,5 +67,20 @@ trail cache. it's not a problem.
- make DUP and SWP work
- make trail work
* done                                                                :entry:
** 2017-01-26 how to write a fsm simulator in javascript.
- try write an easier example before writing the real thing.
- easy example:
  check whether a string has substring "abb".

  states:
  | this state       | event                 | next state                                                                                    |
  |------------------+-----------------------+-----------------------------------------------------------------------------------------------|
  | wait for "a"     | read new character ch | if ch is "a", wait for 1st "b"; otherwise, wait for "a"                                       |
  | wait for 1st "b" | read new character ch | if ch is "b" => wait for 2nd "b"; if ch is "a" => wait for 1st "b"; otherwise => wait for "a" |
  | wait for 2nd "b" | read new character ch | if ch is "b" => succeed; if ch is "a" => wait for 1st "b"; otherwise => wait for "a"          |
  | succeed          | ∅                     | ∅                                                                                             |

- it works.

** 2017-01-26 draw the keyboard using HTML and CSS
* wontfix                                                             :entry: