Set::FA::Element - Discrete Finite Automaton
This is scripts/synopsis.2.pl (a test-free version of t/report.t):
#!/usr/bin/env perl use strict; use warnings; use Set::FA::Element; # -------------------------- my($dfa) = Set::FA::Element -> new ( accepting => ['baz'], maxlevel => 'debug', start => 'foo', transitions => [ ['foo', 'b', 'bar'], ['foo', '.', 'foo'], ['bar', 'a', 'foo'], ['bar', 'b', 'bar'], ['bar', 'c', 'baz'], ['baz', '.', 'baz'], ], ); print "Got: \n"; $dfa -> report; print "Expected: \n", <<EOS; Entered report() State Transition Table State: bar Rule => Next state /a/ => foo /b/ => bar /c/ => baz State: baz. This is an accepting state Rule => Next state /./ => baz State: foo. This is the start state Rule => Next state /b/ => bar /./ => foo EOS Or make use of: my($boolean) = $dfa -> accept($input); my($current) = $dfa -> advance($input); my($state) = $dfa -> current; my($boolean) = $dfa -> final; my($acceptor) = $dfa -> final($state); my($string) = $dfa -> match; my($current) = $dfa -> reset; my($current) = $dfa -> state; my($boolean) = $dfa -> state($state); my($string) = $dfa -> step($input); my($boolean) = $dfa -> step_state($next);
Set::FA::Element provides a mechanism to define and run a DFA.
Install Set::FA as you would for any Perl module:
Perl
Run:
cpanm Set::FA
or run:
sudo cpan Set::FA
or unpack the distro, and then either:
perl Build.PL ./Build ./Build test sudo ./Build install
or:
perl Makefile.PL make (or dmake or nmake) make test make install
You can easily subclass Set::FA::Element by having your subclass use exactly the same logic as in the code, after declaring your Moo-based getters and setters.
new() is called as my($dfa) = Set::FA::Element -> new(k1 => v1, k2 => v2, ...).
new()
my($dfa) = Set::FA::Element -> new(k1 => v1, k2 => v2, ...)
It returns a new object of type Set::FA::Element.
Set::FA::Element
Key-value pairs accepted in the parameter list are as follows. Also, each is also a method, so you can retrieve the value and update it at any time.
Naturally, after the internal state transition table has been constructed (during the call to new()), updates to some of these fields will be ignored. Methods which are effective later are documented.
Provides an arrayref of accepting state names.
This key is optional.
The default is [].
Provides a hashref of entry/exit functions keyed by state name.
This means you can have only 1 entry function and 1 exit function per state.
For a module which gives you the power to have a different entry and exit function for each different regexp which matches the input, see the (as yet unwritten) Set::FA::Manifold.
For a given state name key, the value is a hashref with 1 or 2 of these keys:
The 'entry' key points to a reference to a function to be called upon entry to a state.
Alternately, you can pass in an arrayref, with the function reference as the first element, and a string, e.g. the function name, as the second element.
The point of the [\&fn, 'fn'] version is when you call report(), and the 'fn' string is output.
The 'exit' key points to a reference to a function to be called upon exit from a state.
Each of these functions is called (in method step_state() ) with the DFA object as the only parameter. You use that object to call the methods listed in these docs. See "Synopsis" for a list.
The default is {}.
Provides a way for the code to keep running, or die, when the advance() method determines that input is not being consumed.
Setting die_on_loop to 0 means keep running.
Setting die_on_loop to 1 means the code dies, after outputting an error message.
Retrieve and update the value with the die_on_loop() method.
The default is 0.
Provides a place to store some sort of identifier per DFA object.
Retrieve and update the value with the id() method.
The default is ''.
Specify a logger compatible with Log::Handler, for the lexer and parser to use.
Default: A logger of type Log::Handler which writes to the screen.
To disable logging, just set 'logger' to the empty string (not undef).
This option affects Log::Handler.
See the Log::Handler::Levels docs.
By default nothing is printed.
Typical values are: 'error', 'notice', 'info' and 'debug'.
The default produces no output.
Default: 'notice'.
Default: 'error'.
No lower levels are used.
Provides the name of the start state.
Retrieve and update the value with the start() method.
This key is mandatory.
There is no default.
Provides a complex arrayref of state names and regexps which control the transitions between states.
Each element of this arrayref is itself an arrayref of 3 elements:
The name of the state, which has to match the 'current' state, before other elements of this arrayref are utilized.
The regexp, as a string, against which the input is tested, to determine whether or not to move to the next state.
This string may be a coderef. As such, it should contain 2 pairs of parentheses. The first must capture the matched portion of the input, and the second must capture the unmatched portion of the input.
If it is not a coderef, it is wrapped in qr/($regexp)/ and turned into a coderef which returns the 2 portions of the input as described in the previous sentence.
The code supplies the extra parentheses in the qr// above so that the matched portion of the input can be retrieved with the match() method.
If the regexp does not match, (undef, undef) must be returned by the coderef.
The name of the state to which the DFA will move when the regexp matches the input.
The string which matched, if any, can be retrieved with the match() method.
The name of the new state can be retrieved with the current() method.
Calls "advance($input)".
Returns 1 if the 'current' state - after processing the input - is an accepting state.
Returns 0 otherwise.
See "Using new()" for details.
accepting is a parameter to "new([%args])".
accepting
actions is a parameter to "new([%args])".
actions
Calls "step($input)" repeatedly on the unconsumed portion of the input.
Returns the 'current' state at the end of that process.
Since "step($input)" calls "match($consumed_input)" upon every match, and "step_state($next)" too, you necessarily lose access to the individual portions of the input matched by successive runs of the coderef per transition table entry.
At the end of this process, then, "match($consumed_input)" can only return the last portion matched.
See "step($input)" for advancing the DFA by a single transition.
Logging note:
Then, advance() calls $your_logger -> log(warning => $message) when input is not consumed.
Calls die($message).
Use these parameters to new() to construct a state transition table:
Note: The private method _init() calls validate_params() before calling build_stt(), so if you call accepting($new_accepting), actions($new_actions), start($new_start) and transtions($new_transitions), for some reason, and then call build_stt(), you will miss out on the benefit of calling validate_params(). So don't do that!
Here, the [] indicate an optional parameter.
Returns the 'current' state of the DFA.
Sets the 'current' state of the DFA.
See "Using new()" for details. See also "advance($input)" for a discussion of die_on_loop.
die_on_loop
die_on_loop is a parameter to "new([%args])".
Returns 1 if the 'current' state is an accepting state.
Returns 1 if $state is an accepting state.
id is a parameter to "new([%args])".
id
Calls log($level, $message) on the logger object if that object is defined.
To stop this, set the logger to '' in the call to "new([%args])".
logger is a parameter to "new([%args])".
logger
Get or set the value used by the logger object.
This option is only used if an object of type Log::Handler is ceated, and such an object is created by default. To stop this, set the logger to '' in the call to "new([%args])".
See Log::Handler::Levels.
Typical values are: 'notice', 'info' and 'debug'. The default, 'notice', produces no output.
maxlevel is a parameter to "new([%args])".
maxlevel
minlevel is a parameter to "new([%args])".
minlevel
The constructor. See "Constructor and Initialization".
Returns the portion of the input matched by the most recent step of the DFA.
Sets the internal string which will be returned by calling match().
Log the state transition table, at log level 'info'.
Resets the DFA object to the start state.
Returns the 'current' state, which will be the start state.
Does not reset the id or anything else associated with the object.
start is a parameter to "new([%args])".
start
Returns the 'current' state.
Returns 1 if $state was defined in the transitions arrayref supplied to new().
Advances the DFA by a single transition, if possible.
The code checks each entry in the transitions arrayref supplied to new(), in order, looking for entries whose 1st element ($state) matches the 'current' state.
Upon the first match found (if any), the code runs the coderef in the 2nd element ($rule_sub) of that entry.
If there is a match:
Returns the unconsumed portion of the input.
Performs these steps:
If they match, returns 0 immediately.
transitions is a parameter to "new([%args])".
transitions
Perform validation checks on these parameters to new():
Use Capture::Tiny. See t/report.t for a simple example.
See "Repository" below.
See scripts/synopsis.*.pl.
Note: I have switched to Moo and Log::Handler.
Originally, Set::FA::Element used direct hash access to implement the logic. I did not want to do that. At the same time, I did not want users to incur the overhead of Moose.
So, I've adopted my standard policy of using Moo.
While direct hash access allowed the author of Set::FA::Element to have a hash key and a method with the same name, accept, I can't do that now.
So, the parameter to new() (in Set::FA::Element) is called accepting, and the method is still called accept().
This makes it easy to stop a run-away program during development.
See below for details.
This must be used to name the start state.
The state names are taken from the transitions parameter to new().
This makes it easy to change the quantity of progress reports.
Firstly, Set::FA::Element used Log::Agent. I always use Log::Handler these days.
By default (i.e. without a logger object), Set::FA::Element prints messages to STDOUT, and dies upon errors.
However, by supplying a log object, you can capture these events.
Not only that, you can change the behaviour of your log object at any time, by calling "logger($logger_object)".
Specifically, $logger_object -> log(debug => 'Entered x()') is called at the start of each public method.
Setting your log level to 'debug' will cause these messages to appear.
Setting your log level to anything below 'debug', e.g. 'info, 'notice', 'warning' or 'error', will suppress them.
Also, "step_state($next)" calls:
$self -> log(info => "Stepped from state '$current' to '$next' using rule /$rule/ to match '$match'");
just before it returns.
Setting your log level to anything below 'info', e.g. 'notice', 'warning' or 'error', will suppress this message.
Hence, by setting the log level to 'info', you can log just 1 line per state transition, and no other messages, to minimize output.
Lastly, although this logging mechanism may seem complex, it has distinct advantages:
This method uses a global variable to control the level of logging. This means the code using Set::FA::Element can (also) use Log::Agent and call logconfig(...), which in turn affects the behaviour of the logging calls inside those other modules. I assume this design is deliberate, but I certainly don't like it, because (I suspect) it means any running Perl program which changes the configuration affects all other running programs using Log::Agent.
You can configure your logger object, either before calling new(), or at any later time, by changing "minlevel([$string])" or "maxlevel([$string])".
That allows you complete control over the logging activity.
The only log levels output by this code are (from high to low): debug, info, warning and error.
Error messages are self-documenting, in that when you trigger them, you get to read them...
The file Changes was converted into Changelog.ini by Module::Metadata::Changes.
Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions.
See "Credit" in Set::FA.
See "See Also" in Set::FA.
https://github.com/ronsavage/Set-FA
Email the author, or log a bug on RT:
https://rt.cpan.org/Public/Dist/Display.html?Name=Set::FA
Set::FA::Element was written by Mark Rogaski and Ron Savage <ron@savage.net.au> in 2011.
My homepage: http://savage.net.au/index.html
Australian copyright (c) 2011, Ron Savage.
All Programs of mine are 'OSI Certified Open Source Software'; you can redistribute them and/or modify them under the terms of The Perl License, a copy of which is available at: http://www.opensource.org/licenses/index.html
To install Set::FA, copy and paste the appropriate command in to your terminal.
cpanm
CPAN shell
perl -MCPAN -e shell install Set::FA
For more information on module installation, please visit the detailed CPAN module installation guide.