934 lines
No EOL
64 KiB
HTML
934 lines
No EOL
64 KiB
HTML
|
||
<!DOCTYPE html>
|
||
|
||
|
||
|
||
|
||
<html lang="en">
|
||
<head>
|
||
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
||
|
||
<title>1.7. Extended Example: Text Parser State Machine — Computer Systems Fundamentals</title>
|
||
|
||
<link rel="stylesheet" href="_static/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous" />
|
||
<link rel="stylesheet" href="_static/css/pygments.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/css/normalize.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../JSAV/css/JSAV.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../lib/odsaMOD-min.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/css/jquery-1.11.4-smoothness-ui.css" type="text/css" />
|
||
<link rel="stylesheet" href="../../../lib/odsaStyle-min.css" type="text/css" />
|
||
<link rel="stylesheet" href="_static/css/csf.css" type="text/css" />
|
||
|
||
<style>
|
||
.underline { text-decoration: underline; }
|
||
</style>
|
||
|
||
<script type="text/javascript">
|
||
var DOCUMENTATION_OPTIONS = {
|
||
URL_ROOT: './',
|
||
VERSION: '0.4.1',
|
||
COLLAPSE_INDEX: false,
|
||
FILE_SUFFIX: '.html',
|
||
HAS_SOURCE: true
|
||
};
|
||
</script>
|
||
|
||
<script type="text/x-mathjax-config">
|
||
MathJax.Hub.Config({
|
||
tex2jax: {
|
||
inlineMath: [['$','$'], ['\\(','\\)']],
|
||
displayMath: [ ['$$','$$'], ["\\[","\\]"] ],
|
||
processEscapes: true
|
||
},
|
||
"HTML-CSS": {
|
||
scale: "80"
|
||
}
|
||
});
|
||
</script>
|
||
<link rel="shortcut icon" href="_static/favicon.ico"/>
|
||
<link rel="index" title="Index" href="genindex.html" />
|
||
<link rel="search" title="Search" href="search.html" />
|
||
<link rel="index" title="Computer Systems Fundamentals" href="index.html" />
|
||
<link rel="next" title="1. Processes and OS Basics" href="ProcessesOverview.html" />
|
||
<link rel="prev" title="6. Sequence Models in UML" href="SequenceModels.html" />
|
||
|
||
</head><body>
|
||
|
||
<nav class="navbar navbar-expand-md navbar-dark navbar-custom fixed-top">
|
||
|
||
<a class="navbar-brand py-0" href="index.html"><img src="_static/CSF-Logo-Square-Text.png" alt="OpenCSF Logo" height="40em" class="py-1 px-2 mb-0 align-center rounded-lg bg-white" /></a>
|
||
<!-- Show a navbar toggler on mobile -->
|
||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#defaultNavbars" aria-controls="defaultNavbars" aria-expanded="false" aria-label="Toggle navigation">
|
||
<span class="navbar-toggler-icon"></span>
|
||
</button>
|
||
<div class="collapse navbar-collapse" id="defaultNavbars">
|
||
<ul class="navbar-nav mr-auto">
|
||
<li class="nav-item dropdown">
|
||
<a class="nav-link dropdown-toggle jmu-gold rounded" href="StateModelImplementation.html#" id="navbarDropdownChapters" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Contents</a>
|
||
<div class="dropdown-menu scrollable-menu" role="menu" aria-labelledby="navbarDropdownChapters">
|
||
<a class="dropdown-item" tabindex="-1" href="StateModelImplementation.html#"><b>Chapter 1</b></a>
|
||
<a class="dropdown-item" href="IntroConcSysOverview.html"> 1.1. Introduction to Concurrent Systems</a>
|
||
<a class="dropdown-item" href="SysAndModels.html"> 1.2. Systems and Models</a>
|
||
<a class="dropdown-item" href="Themes.html"> 1.3. Themes and Guiding Principles</a>
|
||
<a class="dropdown-item" href="Architectures.html"> 1.4. System Architectures</a>
|
||
<a class="dropdown-item" href="StateModels.html"> 1.5. State Models in UML</a>
|
||
<a class="dropdown-item" href="SequenceModels.html"> 1.6. Sequence Models in UML</a>
|
||
<a class="dropdown-item" href="StateModelImplementation.html"> 1.7. Extended Example: State Model Implementation</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 2</b></a>
|
||
<a class="dropdown-item" href="ProcessesOverview.html"> 2.1. Processes and OS Basics</a>
|
||
<a class="dropdown-item" href="Multiprogramming.html"> 2.2. Processes and Multiprogramming</a>
|
||
<a class="dropdown-item" href="KernelMechanics.html"> 2.3. Kernel Mechanics</a>
|
||
<a class="dropdown-item" href="Syscall.html"> 2.4. System Call Interface</a>
|
||
<a class="dropdown-item" href="ProcessCycle.html"> 2.5. Process Life Cycle</a>
|
||
<a class="dropdown-item" href="UnixFile.html"> 2.6. The UNIX File Abstraction</a>
|
||
<a class="dropdown-item" href="EventsSignals.html"> 2.7. Events and Signals</a>
|
||
<a class="dropdown-item" href="Extended2Processes.html"> 2.8. Extended Example: Listing Files with Processes</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 3</b></a>
|
||
<a class="dropdown-item" href="IPCOverview.html"> 3.1. Concurrency with IPC</a>
|
||
<a class="dropdown-item" href="IPCModels.html"> 3.2. IPC Models</a>
|
||
<a class="dropdown-item" href="Pipes.html"> 3.3. Pipes and FIFOs</a>
|
||
<a class="dropdown-item" href="MMap.html"> 3.4. Shared Memory With Memory-mapped Files</a>
|
||
<a class="dropdown-item" href="POSIXvSysV.html"> 3.5. POSIX vs. System V IPC</a>
|
||
<a class="dropdown-item" href="MQueues.html"> 3.6. Message Passing With Message Queues</a>
|
||
<a class="dropdown-item" href="ShMem.html"> 3.7. Shared Memory</a>
|
||
<a class="dropdown-item" href="IPCSems.html"> 3.8. Semaphores</a>
|
||
<a class="dropdown-item" href="Extended3Bash.html"> 3.9. Extended Example: Bash-lite: A Simple Command-line Shell</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 4</b></a>
|
||
<a class="dropdown-item" href="SocketsOverview.html"> 4.1. Networked Concurrency</a>
|
||
<a class="dropdown-item" href="FiveLayer.html"> 4.2. The TCP/IP Internet Model</a>
|
||
<a class="dropdown-item" href="NetApps.html"> 4.3. Network Applications and Protocols</a>
|
||
<a class="dropdown-item" href="Sockets.html"> 4.4. The Socket Interface</a>
|
||
<a class="dropdown-item" href="TCPSockets.html"> 4.5. TCP Socket Programming: HTTP</a>
|
||
<a class="dropdown-item" href="UDPSockets.html"> 4.6. UDP Socket Programming: DNS</a>
|
||
<a class="dropdown-item" href="AppBroadcast.html"> 4.7. Application-Layer Broadcasting: DHCP</a>
|
||
<a class="dropdown-item" href="Extended4CGI.html"> 4.8. Extended Example: CGI Web Server</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 5</b></a>
|
||
<a class="dropdown-item" href="InternetOverview.html"> 5.1. The Internet and Connectivity</a>
|
||
<a class="dropdown-item" href="AppLayer.html"> 5.2. Application Layer: Overlay Networks</a>
|
||
<a class="dropdown-item" href="TransLayer.html"> 5.3. Transport Layer</a>
|
||
<a class="dropdown-item" href="NetSec.html"> 5.4. Network Security Fundamentals</a>
|
||
<a class="dropdown-item" href="NetLayer.html"> 5.5. Network Layer: IP</a>
|
||
<a class="dropdown-item" href="LinkLayer.html"> 5.6. Link Layer</a>
|
||
<a class="dropdown-item" href="Wireless.html"> 5.7. Wireless Connectivity: Wi-Fi, Bluetooth, and Zigbee</a>
|
||
<a class="dropdown-item" href="Extended5DNS.html"> 5.8. Extended Example: DNS client</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 6</b></a>
|
||
<a class="dropdown-item" href="ThreadsOverview.html"> 6.1. Concurrency with Multithreading</a>
|
||
<a class="dropdown-item" href="ProcVThreads.html"> 6.2. Processes vs. Threads</a>
|
||
<a class="dropdown-item" href="RaceConditions.html"> 6.3. Race Conditions and Critical Sections</a>
|
||
<a class="dropdown-item" href="POSIXThreads.html"> 6.4. POSIX Thread Library</a>
|
||
<a class="dropdown-item" href="ThreadArgs.html"> 6.5. Thread Arguments and Return Values</a>
|
||
<a class="dropdown-item" href="ImplicitThreads.html"> 6.6. Implicit Threading and Language-based Threads</a>
|
||
<a class="dropdown-item" href="Extended6Input.html"> 6.7. Extended Example: Keyboard Input Listener</a>
|
||
<a class="dropdown-item" href="Extended6Primes.html"> 6.8. Extended Example: Concurrent Prime Number Search</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 7</b></a>
|
||
<a class="dropdown-item" href="SynchOverview.html"> 7.1. Synchronization Primitives</a>
|
||
<a class="dropdown-item" href="CritSect.html"> 7.2. Critical Sections and Peterson's Solution</a>
|
||
<a class="dropdown-item" href="Locks.html"> 7.3. Locks</a>
|
||
<a class="dropdown-item" href="Semaphores.html"> 7.4. Semaphores</a>
|
||
<a class="dropdown-item" href="Barriers.html"> 7.5. Barriers</a>
|
||
<a class="dropdown-item" href="Condvars.html"> 7.6. Condition Variables</a>
|
||
<a class="dropdown-item" href="Deadlock.html"> 7.7. Deadlock</a>
|
||
<a class="dropdown-item" href="Extended7Events.html"> 7.8. Extended Example: Event Log File</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 8</b></a>
|
||
<a class="dropdown-item" href="SynchProblemsOverview.html"> 8.1. Synchronization Patterns and Problems</a>
|
||
<a class="dropdown-item" href="SynchDesign.html"> 8.2. Basic Synchronization Design Patterns</a>
|
||
<a class="dropdown-item" href="ProdCons.html"> 8.3. Producer-Consumer Problem</a>
|
||
<a class="dropdown-item" href="ReadWrite.html"> 8.4. Readers-Writers Problem</a>
|
||
<a class="dropdown-item" href="DiningPhil.html"> 8.5. Dining Philosophers Problem and Deadlock</a>
|
||
<a class="dropdown-item" href="CigSmokers.html"> 8.6. Cigarette Smokers Problem and the Limits of Semaphores and Locks</a>
|
||
<a class="dropdown-item" href="Extended8ModExp.html"> 8.7. Extended Example: Parallel Modular Exponentiation</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Chapter 9</b></a>
|
||
<a class="dropdown-item" href="ParallelDistributedOverview.html"> 9.1. Parallel and Distributed Systems</a>
|
||
<a class="dropdown-item" href="ParVConc.html"> 9.2. Parallelism vs. Concurrency</a>
|
||
<a class="dropdown-item" href="ParallelDesign.html"> 9.3. Parallel Design Patterns</a>
|
||
<a class="dropdown-item" href="Scaling.html"> 9.4. Limits of Parallelism and Scaling</a>
|
||
<a class="dropdown-item" href="DistTiming.html"> 9.5. Timing in Distributed Environments</a>
|
||
<a class="dropdown-item" href="DistDataStorage.html"> 9.6. Reliable Data Storage and Location</a>
|
||
<a class="dropdown-item" href="DistConsensus.html"> 9.7. Consensus in Distributed Systems</a>
|
||
<a class="dropdown-item" href="Extended9Blockchain.html"> 9.8. Extended Example: Blockchain Proof-of-Work</a>
|
||
<div class="dropdown-divider"></div>
|
||
<a class="dropdown-item disabled"><b>Appendix A</b></a>
|
||
<a class="dropdown-item" href="CLangOverview.html"> A.1. C Language Reintroduction</a>
|
||
<a class="dropdown-item" href="Debugging.html"> A.2. Documentation and Debugging</a>
|
||
<a class="dropdown-item" href="BasicTypes.html"> A.3. Basic Types and Pointers</a>
|
||
<a class="dropdown-item" href="Arrays.html"> A.4. Arrays, Structs, Enums, and Type Definitions</a>
|
||
<a class="dropdown-item" href="Functions.html"> A.5. Functions and Scope</a>
|
||
<a class="dropdown-item" href="Pointers.html"> A.6. Pointers and Dynamic Allocation</a>
|
||
<a class="dropdown-item" href="Strings.html"> A.7. Strings</a>
|
||
<a class="dropdown-item" href="FunctionPointers.html"> A.8. Function Pointers</a>
|
||
<a class="dropdown-item" href="Files.html"> A.9. Files</a>
|
||
</div>
|
||
</li>
|
||
|
||
|
||
|
||
</ul>
|
||
</div>
|
||
|
||
<ul class="navbar-nav flex-row ml-md-auto d-none d-md-flex">
|
||
<li class="nav-item"><a class="nav-link jmu-gold" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/Books/csf/source/StateModelImplementation.rst"
|
||
target="_blank" rel="nofollow">Show Source</a></li>
|
||
|
||
</ul>
|
||
</nav>
|
||
|
||
|
||
<div class="container center">
|
||
«  <a id="prevmod" href="SequenceModels.html">1.6. Sequence Models in UML</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod" href="ProcessesOverview.html">2.1. Processes and OS Basics</a>  »
|
||
|
||
</div>
|
||
<br />
|
||
|
||
|
||
|
||
<script type="text/javascript" src="_static/js/jquery-2.1.4.min.js"></script>
|
||
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
|
||
<script type="text/javascript" src="_static/js/jquery-1.11.4-ui.min.js"></script>
|
||
<script type="text/javascript" src="_static/js/forge-0.7.0.min.js"></script>
|
||
<script type="text/javascript" src="../../../JSAV/lib/jquery.transit.js"></script>
|
||
<script type="text/javascript" src="../../../JSAV/lib/raphael.js"></script>
|
||
<script type="text/javascript" src="../../../JSAV/build/JSAV-min.js"></script>
|
||
<script type="text/javascript" src="_static/js/config.js"></script>
|
||
<script type="text/javascript" src="../../../lib/odsaUtils-min.js"></script>
|
||
<script type="text/javascript" src="../../../lib/odsaMOD-min.js"></script>
|
||
<script type="text/javascript" src="_static/js/d3-4.13.0.min.js"></script>
|
||
<script type="text/javascript" src="_static/js/d3-selection-multi.v1.min.js"></script>
|
||
<script type="text/javascript" src="../../../lib/dataStructures.js"></script>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<div class="container">
|
||
|
||
<script>ODSA.SETTINGS.DISP_MOD_COMP = true;ODSA.SETTINGS.MODULE_NAME = "StateModelImplementation";ODSA.SETTINGS.MODULE_LONG_NAME = "Extended Example: Text Parser State Machine";ODSA.SETTINGS.MODULE_CHAPTER = "Introduction to Computer Systems"; ODSA.SETTINGS.BUILD_DATE = "2021-06-14 17:15:25"; ODSA.SETTINGS.BUILD_CMAP = false;JSAV_OPTIONS['lang']='en';JSAV_EXERCISE_OPTIONS['code']='java';</script><div class="section" id="extended-example-text-parser-state-machine">
|
||
<h1>1.7. Extended Example: Text Parser State Machine<a class="headerlink" href="StateModelImplementation.html#extended-example-text-parser-state-machine" title="Permalink to this headline">¶</a></h1>
|
||
<div class="figure mb-2 align-right" id="id3" style="width: 55%">
|
||
<span id="stateparser"></span><a class="reference internal image-reference" href="_images/CSF-Images.1.12.png"><img class="p-3 mb-2 align-center border border-dark rounded-lg" alt="A UML state model for a simple parser" src="_images/CSF-Images.1.12.png" style="width: 95%;" /></a>
|
||
<p class="caption align-center px-3"><span class="caption-text"> Figure 1.7.1: A UML state model for a simple parser</span></p>
|
||
</div>
|
||
<p>In this Extended Example, we will illustrate how to use a state machine as a parser. This is a very
|
||
simplified version of how compilers read in and parse source code. <a href="StateModelImplementation.html#stateparser">Figure 1.7.1</a>
|
||
shows the state model that we will be using to implement the parser. This parser recognizes only the
|
||
strings <code class="docutils literal notranslate"><span class="pre">"int"</span></code> and <code class="docutils literal notranslate"><span class="pre">"integer"</span></code>, rejecting everything else. Both strings are expected to end
|
||
with a space, leading to the Accept final state.</p>
|
||
<p>To reduce the size of the model, the character-recognition events (<code class="docutils literal notranslate"><span class="pre">CHAR_*</span></code>) are fired when the
|
||
corresponding character is read from the input in the correct order. For instance, parsing the
|
||
string <code class="docutils literal notranslate"><span class="pre">"int"</span></code> would fire three events in sequence: <code class="docutils literal notranslate"><span class="pre">CHAR_i</span></code>, <code class="docutils literal notranslate"><span class="pre">CHAR_nt</span></code>, then <code class="docutils literal notranslate"><span class="pre">CHAR_nt</span></code>. On
|
||
the other hand, parsing string <code class="docutils literal notranslate"><span class="pre">"itn"</span></code> would fire the events in sequence: <code class="docutils literal notranslate"><span class="pre">CHAR_i</span></code> then
|
||
<code class="docutils literal notranslate"><span class="pre">CHAR_other</span></code>, because the <code class="docutils literal notranslate"><span class="pre">'t'</span></code> would not be in the correct order. A more complete model would
|
||
use distinct events for each character, as well as separate states to represent the full ordering;
|
||
that is, <code class="docutils literal notranslate"><span class="pre">'i'</span></code> would lead to a one state, then <code class="docutils literal notranslate"><span class="pre">'n'</span></code> would lead to a second, and <code class="docutils literal notranslate"><span class="pre">'t'</span></code> would
|
||
to a third. However, such a model is more difficult to include in the space constraints of the page
|
||
here.</p>
|
||
<p>First, we complete the generic FSM handler, which we described in <a class="reference external" href="StateModelImplementation.html#cl1-1">Code Listing 1.1</a> and <a class="reference external" href="StateModelImplementation.html#cl1-2">1.2</a>. The key
|
||
difference here is that there are some additional fields added to the <code class="docutils literal notranslate"><span class="pre">fsm_t</span></code> declaration. As each
|
||
character of the input is processed, it is added to a buffer that keeps track of the string in
|
||
progress. Also, to assist the controller in determining which events are valid due to the ordering
|
||
of the characters, there are <code class="docutils literal notranslate"><span class="pre">next_valid</span></code> and <code class="docutils literal notranslate"><span class="pre">next_event</span></code> fields. For instance, when the FSM
|
||
first enters the <code class="docutils literal notranslate"><span class="pre">Int_Or_Integer</span></code> state, only the character <code class="docutils literal notranslate"><span class="pre">'i'</span></code> has been processed.
|
||
Consequently the <code class="docutils literal notranslate"><span class="pre">next_valid</span></code> character would be <code class="docutils literal notranslate"><span class="pre">'n'</span></code> and the <code class="docutils literal notranslate"><span class="pre">next_event</span></code> would be
|
||
<code class="docutils literal notranslate"><span class="pre">CHAR_nt</span></code>. However, once the <code class="docutils literal notranslate"><span class="pre">'n'</span></code> is read, the <code class="docutils literal notranslate"><span class="pre">next_valid</span></code> would change to <code class="docutils literal notranslate"><span class="pre">'t'</span></code>
|
||
accordingly. The <code class="docutils literal notranslate"><span class="pre">final</span></code> field is used by the controlling driver program to determine if the
|
||
string was read completely.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
19
|
||
20
|
||
21
|
||
22
|
||
23
|
||
24
|
||
25
|
||
26
|
||
27
|
||
28
|
||
29
|
||
30
|
||
31
|
||
32
|
||
33
|
||
34
|
||
35
|
||
36
|
||
37
|
||
38
|
||
39
|
||
40
|
||
41
|
||
42
|
||
43
|
||
44
|
||
45</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cp">#ifndef __statemodel_h__</span>
|
||
<span class="cp">#define __statemodel_h__</span>
|
||
|
||
<span class="cp">#include</span> <span class="cpf"><stdbool.h></span><span class="cp"></span>
|
||
<span class="cp">#include</span> <span class="cpf"><sys/types.h></span><span class="cp"></span>
|
||
|
||
<span class="cm">/* States and events should just be integers */</span>
|
||
<span class="k">typedef</span> <span class="kt">int</span> <span class="n">state_t</span><span class="p">;</span>
|
||
<span class="k">typedef</span> <span class="kt">int</span> <span class="n">event_t</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Dummy struct for circular typedefs */</span>
|
||
<span class="k">struct</span> <span class="n">fsm</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Function pointer type declaration for effects */</span>
|
||
<span class="k">typedef</span> <span class="nf">void</span> <span class="p">(</span><span class="o">*</span><span class="n">action_t</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">fsm</span> <span class="o">*</span><span class="p">);</span>
|
||
|
||
<span class="cp">#define BUFFER_LENGTH 10</span>
|
||
|
||
<span class="cm">/* Generic FSM struct that could have other fields, as well */</span>
|
||
<span class="k">typedef</span> <span class="k">struct</span> <span class="n">fsm</span> <span class="p">{</span>
|
||
<span class="n">state_t</span> <span class="n">state</span><span class="p">;</span> <span class="cm">/* current state */</span>
|
||
<span class="kt">size_t</span> <span class="n">nevents</span><span class="p">;</span> <span class="cm">/* number of events for this FSM */</span>
|
||
|
||
<span class="cm">/* pointer to the FSM's transition function */</span>
|
||
<span class="n">state_t</span> <span class="p">(</span><span class="o">*</span><span class="n">transition</span><span class="p">)</span> <span class="p">(</span><span class="k">struct</span> <span class="n">fsm</span> <span class="o">*</span><span class="p">,</span> <span class="n">event_t</span><span class="p">,</span> <span class="n">action_t</span> <span class="o">*</span><span class="p">,</span> <span class="n">action_t</span> <span class="o">*</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* helper fields to keep track of the current input and the</span>
|
||
<span class="cm"> string built so far */</span>
|
||
<span class="kt">char</span> <span class="n">input</span><span class="p">;</span>
|
||
<span class="kt">char</span> <span class="n">buffer</span><span class="p">[</span><span class="n">BUFFER_LENGTH</span><span class="p">];</span>
|
||
<span class="kt">size_t</span> <span class="n">length</span><span class="p">;</span>
|
||
|
||
<span class="kt">bool</span> <span class="n">final</span><span class="p">;</span> <span class="cm">/* set on accept or reject */</span>
|
||
|
||
<span class="cm">/* special handling: since there are self-transitions that are</span>
|
||
<span class="cm"> valid a limited number of times, use these fields to keep</span>
|
||
<span class="cm"> track of the next event to fire based on expected input */</span>
|
||
<span class="kt">char</span> <span class="n">next_valid</span><span class="p">;</span>
|
||
<span class="n">event_t</span> <span class="n">next_event</span><span class="p">;</span>
|
||
<span class="p">}</span> <span class="n">fsm_t</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Invoke an event handler for a given FSM */</span>
|
||
<span class="kt">void</span> <span class="nf">handle_event</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="n">fsm</span><span class="p">,</span> <span class="n">event_t</span> <span class="n">event</span><span class="p">);</span>
|
||
|
||
<span class="cp">#endif</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>Next, we extend <a class="reference external" href="StateModelImplementation.html#cl1-2">Code Listing 1.2</a> so that it can also perform entry activities on state changes.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
19
|
||
20
|
||
21
|
||
22
|
||
23
|
||
24
|
||
25
|
||
26
|
||
27
|
||
28
|
||
29
|
||
30
|
||
31</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
|
||
<span class="cp">#include</span> <span class="cpf"><stdlib.h></span><span class="cp"></span>
|
||
|
||
<span class="cp">#include</span> <span class="cpf">"statemodel.h"</span><span class="cp"></span>
|
||
|
||
<span class="kt">void</span>
|
||
<span class="nf">handle_event</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="n">fsm</span><span class="p">,</span> <span class="n">event_t</span> <span class="n">event</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="cm">/* Confirm the event is valid for the given FSM */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">event</span> <span class="o">>=</span> <span class="n">fsm</span><span class="o">-></span><span class="n">nevents</span><span class="p">)</span>
|
||
<span class="k">return</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Use the FSM's lookup tables; if next is -1, the event is not</span>
|
||
<span class="cm"> Defined for the current state */</span>
|
||
<span class="n">action_t</span> <span class="n">effect</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
|
||
<span class="n">action_t</span> <span class="n">entry</span> <span class="o">=</span> <span class="nb">NULL</span><span class="p">;</span>
|
||
<span class="n">state_t</span> <span class="n">next</span> <span class="o">=</span> <span class="n">fsm</span><span class="o">-></span><span class="n">transition</span> <span class="p">(</span><span class="n">fsm</span><span class="p">,</span> <span class="n">event</span><span class="p">,</span> <span class="o">&</span><span class="n">effect</span><span class="p">,</span> <span class="o">&</span><span class="n">entry</span><span class="p">);</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">next</span> <span class="o">==</span> <span class="o">-</span><span class="mi">1</span><span class="p">)</span>
|
||
<span class="k">return</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Perform the effect (if defined) */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">effect</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span>
|
||
<span class="n">effect</span> <span class="p">(</span><span class="n">fsm</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Perform the new state's entry action (if defined) */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">entry</span> <span class="o">!=</span> <span class="nb">NULL</span><span class="p">)</span>
|
||
<span class="n">entry</span> <span class="p">(</span><span class="n">fsm</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Change the state */</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">state</span> <span class="o">=</span> <span class="n">next</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>The <code class="docutils literal notranslate"><span class="pre">"parse.h"</span></code> header file defines the interface to this specific FSM. To control the parser FSM,
|
||
a driver program would need access to the event names (defined by the <code class="docutils literal notranslate"><span class="pre">parse_event_t</span></code> type) and
|
||
the name of the initialization function.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cp">#ifndef __parse_h__</span>
|
||
<span class="cp">#define __parse_h__</span>
|
||
|
||
<span class="cp">#include</span> <span class="cpf">"statemodel.h"</span><span class="cp"></span>
|
||
|
||
<span class="cm">/* Valid events for this type of FSM */</span>
|
||
<span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span>
|
||
<span class="n">CHAR_i</span><span class="p">,</span> <span class="n">CHAR_nt</span><span class="p">,</span> <span class="n">CHAR_e</span><span class="p">,</span> <span class="n">CHAR_ger</span><span class="p">,</span> <span class="n">CHAR_other</span><span class="p">,</span> <span class="n">SPACE</span><span class="p">,</span> <span class="n">NIL</span>
|
||
<span class="p">}</span> <span class="n">parse_event_t</span><span class="p">;</span>
|
||
|
||
<span class="n">fsm_t</span> <span class="o">*</span><span class="nf">parse_init</span> <span class="p">(</span><span class="kt">void</span><span class="p">);</span>
|
||
|
||
<span class="cp">#endif</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>The next piece of code extends <a class="reference external" href="StateModelImplementation.html#cl1-3">Code Listing 1.3</a> with the information needed for the parser
|
||
structure. As before, there’s an initialization function (<code class="docutils literal notranslate"><span class="pre">parse_init()</span></code>) that sets up the
|
||
internals of the <code class="docutils literal notranslate"><span class="pre">fsm_t</span></code>. The <code class="docutils literal notranslate"><span class="pre">append_character()</span></code> function keeps track of how many times each
|
||
particular state has been visited and what character is expected next. Again, a more verbose FSM
|
||
would not need this information. Finally, the <code class="docutils literal notranslate"><span class="pre">accept()</span></code> and <code class="docutils literal notranslate"><span class="pre">reject()</span></code> functions implement the
|
||
transition effects.</p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
19
|
||
20
|
||
21
|
||
22
|
||
23
|
||
24
|
||
25
|
||
26
|
||
27
|
||
28
|
||
29
|
||
30
|
||
31
|
||
32
|
||
33
|
||
34
|
||
35
|
||
36
|
||
37
|
||
38
|
||
39
|
||
40
|
||
41
|
||
42
|
||
43
|
||
44
|
||
45
|
||
46
|
||
47
|
||
48
|
||
49
|
||
50
|
||
51
|
||
52
|
||
53
|
||
54
|
||
55
|
||
56
|
||
57
|
||
58
|
||
59
|
||
60
|
||
61
|
||
62
|
||
63
|
||
64
|
||
65
|
||
66
|
||
67
|
||
68
|
||
69
|
||
70
|
||
71
|
||
72
|
||
73
|
||
74
|
||
75
|
||
76
|
||
77
|
||
78
|
||
79
|
||
80
|
||
81
|
||
82
|
||
83
|
||
84
|
||
85
|
||
86
|
||
87
|
||
88
|
||
89
|
||
90
|
||
91
|
||
92
|
||
93
|
||
94
|
||
95
|
||
96
|
||
97
|
||
98
|
||
99
|
||
100
|
||
101
|
||
102
|
||
103
|
||
104
|
||
105
|
||
106
|
||
107
|
||
108
|
||
109
|
||
110
|
||
111
|
||
112
|
||
113
|
||
114
|
||
115
|
||
116
|
||
117
|
||
118
|
||
119
|
||
120
|
||
121
|
||
122
|
||
123
|
||
124
|
||
125
|
||
126
|
||
127
|
||
128
|
||
129
|
||
130
|
||
131
|
||
132
|
||
133
|
||
134
|
||
135
|
||
136
|
||
137
|
||
138
|
||
139</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cp">#include</span> <span class="cpf"><assert.h></span><span class="cp"></span>
|
||
<span class="cp">#include</span> <span class="cpf"><stdbool.h></span><span class="cp"></span>
|
||
<span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
|
||
<span class="cp">#include</span> <span class="cpf"><stdlib.h></span><span class="cp"></span>
|
||
<span class="cp">#include</span> <span class="cpf"><string.h></span><span class="cp"></span>
|
||
|
||
<span class="cp">#include</span> <span class="cpf">"statemodel.h"</span><span class="cp"></span>
|
||
<span class="cp">#include</span> <span class="cpf">"parser.h"</span><span class="cp"></span>
|
||
|
||
<span class="cm">/* Internal type definition of states */</span>
|
||
<span class="k">typedef</span> <span class="k">enum</span> <span class="p">{</span> <span class="n">ENTER</span><span class="p">,</span> <span class="n">IOI</span><span class="p">,</span> <span class="n">IO</span><span class="p">,</span> <span class="n">ACCEPT</span><span class="p">,</span> <span class="n">FAIL</span><span class="p">,</span> <span class="n">NST</span> <span class="p">}</span> <span class="n">parse_t</span><span class="p">;</span>
|
||
<span class="cp">#define NUM_STATES (NST+1)</span>
|
||
<span class="cp">#define NUM_EVENTS (NIL+1)</span>
|
||
|
||
<span class="cm">/* Prototypes for actions/effects and transition function */</span>
|
||
<span class="k">static</span> <span class="kt">void</span> <span class="nf">append_character</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="p">);</span>
|
||
<span class="k">static</span> <span class="kt">void</span> <span class="nf">accept</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="p">);</span>
|
||
<span class="k">static</span> <span class="kt">void</span> <span class="nf">reject</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="p">);</span>
|
||
<span class="k">static</span> <span class="n">state_t</span> <span class="nf">parse_transition</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="p">,</span> <span class="n">event_t</span><span class="p">,</span> <span class="n">action_t</span> <span class="o">*</span><span class="p">,</span> <span class="n">action_t</span> <span class="o">*</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* Return an FSM that links to these internals */</span>
|
||
<span class="n">fsm_t</span> <span class="o">*</span>
|
||
<span class="nf">parse_init</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">fsm_t</span> <span class="o">*</span><span class="n">fsm</span> <span class="o">=</span> <span class="n">calloc</span> <span class="p">(</span><span class="mi">1</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">fsm_t</span><span class="p">));</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">nevents</span> <span class="o">=</span> <span class="n">NUM_EVENTS</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">state</span> <span class="o">=</span> <span class="n">ENTER</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">transition</span> <span class="o">=</span> <span class="n">parse_transition</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Set up internal fields for keeping track of characters */</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">input</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
|
||
<span class="n">memset</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">,</span> <span class="mi">0</span><span class="p">,</span> <span class="k">sizeof</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">));</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">length</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
|
||
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_valid</span> <span class="o">=</span> <span class="sc">'i'</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_event</span> <span class="o">=</span> <span class="n">CHAR_i</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">final</span> <span class="o">=</span> <span class="nb">false</span><span class="p">;</span>
|
||
|
||
<span class="k">return</span> <span class="n">fsm</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="cm">/* Lookup table for transitions; row=state, column=event */</span>
|
||
<span class="k">static</span> <span class="n">parse_t</span> <span class="k">const</span> <span class="n">_transition</span><span class="p">[</span><span class="n">NUM_STATES</span><span class="p">][</span><span class="n">NUM_EVENTS</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="c1">// C_i C_nt C_e C_ger C_oth SPACE</span>
|
||
<span class="p">{</span> <span class="n">IOI</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">FAIL</span><span class="p">,</span> <span class="n">NST</span> <span class="p">},</span> <span class="c1">// Enter</span>
|
||
<span class="p">{</span> <span class="n">NST</span><span class="p">,</span> <span class="n">IOI</span><span class="p">,</span> <span class="n">IO</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">FAIL</span><span class="p">,</span> <span class="n">ACCEPT</span> <span class="p">},</span> <span class="c1">// Int_Or_Integer</span>
|
||
<span class="p">{</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">IO</span><span class="p">,</span> <span class="n">FAIL</span><span class="p">,</span> <span class="n">ACCEPT</span> <span class="p">},</span> <span class="c1">// Integer_Only</span>
|
||
<span class="p">{</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span> <span class="p">},</span> <span class="c1">// Accept</span>
|
||
<span class="p">{</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span><span class="p">,</span> <span class="n">NST</span> <span class="p">},</span> <span class="c1">// Fail</span>
|
||
<span class="p">};</span>
|
||
|
||
<span class="cm">/* Lookup table for effects; row=state, column=event */</span>
|
||
<span class="k">static</span> <span class="n">action_t</span> <span class="k">const</span> <span class="n">_effect</span><span class="p">[</span><span class="n">NUM_STATES</span><span class="p">][</span><span class="n">NUM_EVENTS</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="c1">// C_i C_nt C_e C_ger C_oth SPACE</span>
|
||
<span class="p">{</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">reject</span><span class="p">,</span> <span class="nb">NULL</span> <span class="p">},</span> <span class="c1">// Enter</span>
|
||
<span class="p">{</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">reject</span><span class="p">,</span> <span class="n">accept</span> <span class="p">},</span> <span class="c1">// Int_Or_Integer</span>
|
||
<span class="p">{</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="n">reject</span><span class="p">,</span> <span class="n">accept</span> <span class="p">},</span> <span class="c1">// Integer_Only</span>
|
||
<span class="p">{</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span> <span class="p">},</span> <span class="c1">// Accept</span>
|
||
<span class="p">{</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span> <span class="p">},</span> <span class="c1">// Fail</span>
|
||
<span class="p">};</span>
|
||
|
||
<span class="cm">/* Lookup table for state entry actions */</span>
|
||
<span class="k">static</span> <span class="n">action_t</span> <span class="k">const</span> <span class="n">_entry</span><span class="p">[</span><span class="n">NUM_STATES</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span>
|
||
<span class="nb">NULL</span><span class="p">,</span> <span class="n">append_character</span><span class="p">,</span> <span class="n">append_character</span><span class="p">,</span> <span class="nb">NULL</span><span class="p">,</span> <span class="nb">NULL</span>
|
||
<span class="p">};</span>
|
||
|
||
<span class="cm">/* Given FSM instance and event, perform the table lookups */</span>
|
||
<span class="k">static</span> <span class="n">state_t</span>
|
||
<span class="nf">parse_transition</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="n">fsm</span><span class="p">,</span> <span class="n">event_t</span> <span class="n">event</span><span class="p">,</span> <span class="n">action_t</span> <span class="o">*</span><span class="n">effect</span><span class="p">,</span> <span class="n">action_t</span> <span class="o">*</span><span class="n">entry</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="cm">/* If the state/event combination is bad, return -1 */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">state</span> <span class="o">>=</span> <span class="n">NST</span> <span class="o">||</span> <span class="n">event</span> <span class="o">>=</span> <span class="n">NIL</span> <span class="o">||</span> <span class="n">_transition</span><span class="p">[</span><span class="n">fsm</span><span class="o">-></span><span class="n">state</span><span class="p">][</span><span class="n">event</span><span class="p">]</span> <span class="o">==</span> <span class="n">NST</span><span class="p">)</span>
|
||
<span class="k">return</span> <span class="o">-</span><span class="mi">1</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Look up the effect and transitions in the tables */</span>
|
||
<span class="o">*</span><span class="n">effect</span> <span class="o">=</span> <span class="n">_effect</span><span class="p">[</span><span class="n">fsm</span><span class="o">-></span><span class="n">state</span><span class="p">][</span><span class="n">event</span><span class="p">];</span>
|
||
|
||
<span class="cm">/* Look up the next state in the list of entry events */</span>
|
||
<span class="n">state_t</span> <span class="n">next</span> <span class="o">=</span> <span class="n">_transition</span><span class="p">[</span><span class="n">fsm</span><span class="o">-></span><span class="n">state</span><span class="p">][</span><span class="n">event</span><span class="p">];</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">next</span> <span class="o">!=</span> <span class="n">NST</span><span class="p">)</span>
|
||
<span class="o">*</span><span class="n">entry</span> <span class="o">=</span> <span class="n">_entry</span><span class="p">[</span><span class="n">next</span><span class="p">];</span>
|
||
|
||
<span class="k">return</span> <span class="n">next</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="cm">/* Appends the current character to the buffer */</span>
|
||
<span class="k">static</span> <span class="kt">void</span>
|
||
<span class="nf">append_character</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="n">fsm</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">assert</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">length</span> <span class="o"><</span> <span class="n">BUFFER_LENGTH</span> <span class="o">-</span> <span class="mi">1</span><span class="p">);</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">[</span><span class="n">fsm</span><span class="o">-></span><span class="n">length</span><span class="o">++</span><span class="p">]</span> <span class="o">=</span> <span class="n">fsm</span><span class="o">-></span><span class="n">input</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Helper inputs to keep track of what the next event will be */</span>
|
||
<span class="k">switch</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">input</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="k">case</span> <span class="sc">'i'</span><span class="o">:</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_valid</span> <span class="o">=</span> <span class="sc">'n'</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_event</span> <span class="o">=</span> <span class="n">CHAR_nt</span><span class="p">;</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
<span class="k">case</span> <span class="sc">'n'</span><span class="o">:</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_valid</span> <span class="o">=</span> <span class="sc">'t'</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_event</span> <span class="o">=</span> <span class="n">CHAR_nt</span><span class="p">;</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
<span class="k">case</span> <span class="sc">'t'</span><span class="o">:</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_valid</span> <span class="o">=</span> <span class="sc">'e'</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_event</span> <span class="o">=</span> <span class="n">CHAR_e</span><span class="p">;</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
<span class="k">case</span> <span class="sc">'e'</span><span class="o">:</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">strcmp</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">,</span> <span class="s">"inte"</span><span class="p">))</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_valid</span> <span class="o">=</span> <span class="sc">'g'</span><span class="p">;</span>
|
||
<span class="k">else</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_valid</span> <span class="o">=</span> <span class="sc">'r'</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_event</span> <span class="o">=</span> <span class="n">CHAR_ger</span><span class="p">;</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
<span class="k">case</span> <span class="sc">'g'</span><span class="o">:</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_valid</span> <span class="o">=</span> <span class="sc">'e'</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_event</span> <span class="o">=</span> <span class="n">CHAR_ger</span><span class="p">;</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
<span class="k">default</span><span class="o">:</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_valid</span> <span class="o">=</span> <span class="sc">'\0'</span><span class="p">;</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">next_event</span> <span class="o">=</span> <span class="n">NIL</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="cm">/* Prints that the string is accepted */</span>
|
||
<span class="k">static</span> <span class="kt">void</span>
|
||
<span class="nf">accept</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="n">fsm</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"ACCEPT: </span><span class="se">\"</span><span class="s">%s</span><span class="se">\"\n</span><span class="s">"</span><span class="p">,</span> <span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">);</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">final</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="cm">/* Prints that the string is rejected and at what character */</span>
|
||
<span class="k">static</span> <span class="kt">void</span>
|
||
<span class="nf">reject</span> <span class="p">(</span><span class="n">fsm_t</span> <span class="o">*</span><span class="n">fsm</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"REJECT: </span><span class="se">\"</span><span class="s">%s</span><span class="se">\"</span><span class="s"> at character '%c'</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span> <span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">,</span> <span class="n">fsm</span><span class="o">-></span><span class="n">input</span><span class="p">);</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">final</span> <span class="o">=</span> <span class="nb">true</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<p>The final piece of code for this parser is the main driver program. This program reads in the
|
||
command-line arguments and attempts to parse each one as beginning with either <code class="docutils literal notranslate"><span class="pre">"int"</span></code> or
|
||
<code class="docutils literal notranslate"><span class="pre">"integer"</span></code>. For each provided input, this controller will use <code class="docutils literal notranslate"><span class="pre">parse_init()</span></code> to create a new
|
||
FSM instance. The code in lines 37 – 48 start by checking for a space (indicating the first token
|
||
of the input has been read) or for the expected next character (based on the information stored in
|
||
the FSM). Based on these checks, line 52 fires the event and the pointer moves on to the next
|
||
character. If all characters have been read, there are three possibilities: 1) a space was found and
|
||
the match was a success 2) the match already failed, or 3) the input has matched a prefix of
|
||
<code class="docutils literal notranslate"><span class="pre">"int"</span></code> or <code class="docutils literal notranslate"><span class="pre">"integer"</span></code>, but there was no space to terminate the string. To resolve case 3, we
|
||
just need to check the strings. <a class="footnote-reference" href="StateModelImplementation.html#f6" id="id2">[1]</a></p>
|
||
<div class="highlight-c border border-dark rounded-lg bg-light px-0 mb-3 notranslate"><table class="highlighttable"><tr><td class="linenos px-0 mx-0"><div class="linenodiv"><pre class="mb-0"> 1
|
||
2
|
||
3
|
||
4
|
||
5
|
||
6
|
||
7
|
||
8
|
||
9
|
||
10
|
||
11
|
||
12
|
||
13
|
||
14
|
||
15
|
||
16
|
||
17
|
||
18
|
||
19
|
||
20
|
||
21
|
||
22
|
||
23
|
||
24
|
||
25
|
||
26
|
||
27
|
||
28
|
||
29
|
||
30
|
||
31
|
||
32
|
||
33
|
||
34
|
||
35
|
||
36
|
||
37
|
||
38
|
||
39
|
||
40
|
||
41
|
||
42
|
||
43
|
||
44
|
||
45
|
||
46
|
||
47
|
||
48
|
||
49
|
||
50
|
||
51
|
||
52
|
||
53
|
||
54
|
||
55
|
||
56
|
||
57
|
||
58
|
||
59
|
||
60
|
||
61
|
||
62
|
||
63
|
||
64
|
||
65
|
||
66
|
||
67
|
||
68
|
||
69
|
||
70
|
||
71
|
||
72
|
||
73
|
||
74
|
||
75
|
||
76
|
||
77
|
||
78</pre></div></td><td class="code"><div class="highlight bg-light"><pre class="mb-0"><span></span><span class="cp">#include</span> <span class="cpf"><stdio.h></span><span class="cp"></span>
|
||
<span class="cp">#include</span> <span class="cpf"><string.h></span><span class="cp"></span>
|
||
|
||
<span class="cp">#include</span> <span class="cpf">"statemodel.h"</span><span class="cp"></span>
|
||
<span class="cp">#include</span> <span class="cpf">"parser.h"</span><span class="cp"></span>
|
||
|
||
<span class="kt">int</span>
|
||
<span class="nf">main</span> <span class="p">(</span><span class="kt">int</span> <span class="n">argc</span><span class="p">,</span> <span class="kt">char</span> <span class="o">*</span><span class="n">argv</span><span class="p">[])</span>
|
||
<span class="p">{</span>
|
||
<span class="cm">/* Inputs to parse. Matches will be exactly "int", "integer",</span>
|
||
<span class="cm"> or begin with "int " or "integer ". */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">argc</span> <span class="o"><</span> <span class="mi">2</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Must pass at least one string argument</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
<span class="n">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">"Sample command line:</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
<span class="n">fprintf</span> <span class="p">(</span><span class="n">stderr</span><span class="p">,</span> <span class="s">" ./ext int char </span><span class="se">\"</span><span class="s">i n t</span><span class="se">\"</span><span class="s"> integ</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
<span class="k">return</span> <span class="mi">1</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="k">for</span> <span class="p">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span> <span class="n">i</span> <span class="o"><</span> <span class="n">argc</span><span class="p">;</span> <span class="n">i</span><span class="o">++</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"Processing input: </span><span class="se">\"</span><span class="s">%s</span><span class="se">\"\n</span><span class="s">"</span><span class="p">,</span> <span class="n">argv</span><span class="p">[</span><span class="n">i</span><span class="p">]);</span>
|
||
|
||
<span class="cm">/* Create a new parser instance for each input */</span>
|
||
<span class="n">fsm_t</span> <span class="o">*</span><span class="n">fsm</span> <span class="o">=</span> <span class="n">parse_init</span> <span class="p">();</span>
|
||
<span class="kt">char</span> <span class="o">*</span><span class="n">walker</span> <span class="o">=</span> <span class="n">argv</span><span class="p">[</span><span class="n">i</span><span class="p">];</span>
|
||
<span class="n">event_t</span> <span class="n">evt</span> <span class="o">=</span> <span class="n">NIL</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Traverse through each character in the input */</span>
|
||
<span class="k">while</span> <span class="p">(</span><span class="o">*</span><span class="n">walker</span> <span class="o">!=</span> <span class="sc">'\0'</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">input</span> <span class="o">=</span> <span class="o">*</span><span class="n">walker</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* If the input is a space, check if the string</span>
|
||
<span class="cm"> match is successful. Otherwise, check if the</span>
|
||
<span class="cm"> next character matches what is expected. */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">input</span> <span class="o">==</span> <span class="sc">' '</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">strcmp</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">,</span> <span class="s">"int"</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span> <span class="n">strcmp</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">,</span> <span class="s">"integer"</span><span class="p">))</span>
|
||
<span class="n">evt</span> <span class="o">=</span> <span class="n">SPACE</span><span class="p">;</span>
|
||
<span class="k">else</span>
|
||
<span class="n">evt</span> <span class="o">=</span> <span class="n">CHAR_other</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
<span class="k">else</span> <span class="k">if</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">input</span> <span class="o">==</span> <span class="n">fsm</span><span class="o">-></span><span class="n">next_valid</span><span class="p">)</span>
|
||
<span class="n">evt</span> <span class="o">=</span> <span class="n">fsm</span><span class="o">-></span><span class="n">next_event</span><span class="p">;</span>
|
||
<span class="k">else</span>
|
||
<span class="n">evt</span> <span class="o">=</span> <span class="n">CHAR_other</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* The event should never be NIL because of the</span>
|
||
<span class="cm"> logic above, but this style is for consistency. */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">evt</span> <span class="o">!=</span> <span class="n">NIL</span><span class="p">)</span>
|
||
<span class="n">handle_event</span> <span class="p">(</span><span class="n">fsm</span><span class="p">,</span> <span class="n">evt</span><span class="p">);</span>
|
||
|
||
<span class="cm">/* If a string is accepted or rejected, we are done. */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">final</span><span class="p">)</span>
|
||
<span class="k">break</span><span class="p">;</span>
|
||
|
||
<span class="cm">/* Move to the next input character. */</span>
|
||
<span class="n">walker</span><span class="o">++</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="cm">/* At the end of the input. Either we have matched exactly</span>
|
||
<span class="cm"> "int" or "integer", or we have matched a substring (such</span>
|
||
<span class="cm"> as "inte"). Substrings should be rejected. Use '$' to</span>
|
||
<span class="cm"> indicate an END-OF-STRING character. */</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="n">fsm</span><span class="o">-></span><span class="n">final</span><span class="p">)</span>
|
||
<span class="p">{</span>
|
||
<span class="n">fsm</span><span class="o">-></span><span class="n">input</span> <span class="o">=</span> <span class="sc">'$'</span><span class="p">;</span>
|
||
<span class="k">if</span> <span class="p">(</span><span class="o">!</span> <span class="n">strcmp</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">,</span> <span class="s">"int"</span><span class="p">)</span> <span class="o">||</span> <span class="o">!</span> <span class="n">strcmp</span> <span class="p">(</span><span class="n">fsm</span><span class="o">-></span><span class="n">buffer</span><span class="p">,</span> <span class="s">"integer"</span><span class="p">))</span>
|
||
<span class="n">handle_event</span> <span class="p">(</span><span class="n">fsm</span><span class="p">,</span> <span class="n">SPACE</span><span class="p">);</span>
|
||
<span class="k">else</span>
|
||
<span class="n">handle_event</span> <span class="p">(</span><span class="n">fsm</span><span class="p">,</span> <span class="n">CHAR_other</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
<span class="n">printf</span> <span class="p">(</span><span class="s">"</span><span class="se">\n</span><span class="s">"</span><span class="p">);</span>
|
||
<span class="p">}</span>
|
||
|
||
<span class="k">return</span> <span class="mi">0</span><span class="p">;</span>
|
||
<span class="p">}</span>
|
||
</pre></div>
|
||
</td></tr></table></div>
|
||
<table class="docutils footnote" frame="void" id="f6" rules="none">
|
||
<colgroup><col class="label" /><col /></colgroup>
|
||
<tbody valign="top">
|
||
<tr><td class="label"><a class="fn-backref" href="StateModelImplementation.html#id2">[1]</a></td><td>One may object at this point and ask why we didn’t just compare the strings from the
|
||
beginning and avoid all of the FSM complexity. The answer is that this example is one miniscule
|
||
component of a much larger system: a compiler. The state models used for compilers are
|
||
significantly larger and distinguish keywords (such as <code class="docutils literal notranslate"><span class="pre">"int"</span></code>) from programmer-defined variable
|
||
names (such as <code class="docutils literal notranslate"><span class="pre">"interest_rate"</span></code>). Simple string comparison is not a feasible approach to such
|
||
complex work.</td></tr>
|
||
</tbody>
|
||
</table>
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
|
||
|
||
<div class="container">
|
||
|
||
<div class="mt-4 container center">
|
||
«  <a id="prevmod1" href="SequenceModels.html">1.6. Sequence Models in UML</a>
|
||
  ::  
|
||
<a class="uplink" href="index.html">Contents</a>
|
||
  ::  
|
||
<a id="nextmod1" href="ProcessesOverview.html">2.1. Processes and OS Basics</a>  »
|
||
</div>
|
||
|
||
|
||
</div>
|
||
|
||
<br />
|
||
|
||
<div class="row jmu-dark-purple-bg">
|
||
<div class="col-md-12">
|
||
<center>
|
||
<a id="contact_us" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="mailto:webmaster@opencsf.org" role="button">Contact Us</a>
|
||
<a id="license" class="btn button-link-no-blue jmu-gold" rel="nofollow" href="https://w3.cs.jmu.edu/kirkpams/OpenCSF/lib/license.html" target="_blank">License</a>
|
||
</center>
|
||
</div>
|
||
</div>
|
||
|
||
|
||
|
||
|
||
|
||
|
||
<script src="_static/js/popper.js-1.14.7-min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
|
||
<script src="_static/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
|
||
</body>
|
||
</html> |