⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ch3.htm

📁 《Perl 5 Unreleased》
💻 HTM
📖 第 1 页 / 共 5 页
字号:
31            if

($a eq '2')&nbsp;&nbsp;{ return(2); }<BR>

32&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '3')&nbsp;&nbsp;{ return(3); }<BR>

33&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return

2;<BR>

34&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};

<BR>

35 # --------------------------------------------------------------

<BR>

36 $s3 = sub {<BR>

37&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;my&nbsp;&nbsp;$a

= shift @_;<BR>

38&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print

&quot;State 3 processing $a \n&quot;;<BR>

39&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '0')&nbsp;&nbsp;{ return(0); }<BR>

40&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '1')&nbsp;&nbsp;{ return(1); }<BR>

41&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '2')&nbsp;&nbsp;{ return(2); }<BR>

42&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($a eq '3')&nbsp;&nbsp;{ return(3); }<BR>

43&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return

3;<BR>

44&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};

<BR>

45 # --------------------------------------------------------------

<BR>

46 # Create an array of pointers to subroutines. The index<BR>

47 # into this array is the current state.<BR>

48 # --------------------------------------------------------------

<BR>

49 @stateTable = ($s0, $s1, $s2, $s3);<BR>

50 # --------------------------------------------------------------

<BR>

51 # Initialize the state to 0.<BR>

52 # --------------------------------------------------------------

<BR>

53 $this = 0;<BR>

54 # --------------------------------------------------------------

<BR>

55 # Implement the state machine.<BR>

56 #&nbsp;&nbsp;&nbsp;set current state to 0<BR>

57 #&nbsp;&nbsp;&nbsp;forever<BR>

58 #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;get response

<BR>

59 #&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;set current

state to next state based on response.<BR>

60 # --------------------------------------------------------------

<BR>

61 while (1)<BR>

62&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{

<BR>

63&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print

&quot;\n This state is : $this -&gt; what next? &quot;;<BR>

64&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$reply

= &lt;STDIN&gt;;<BR>

65&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chop($reply);

<BR>

66&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

<BR>

67&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

Stop the machine here<BR>

68&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

<BR>

69&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if

($reply eq 'q') { exit(0); }<BR>

70&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print

&quot; Reply = $reply \n&quot;;<BR>

71&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

<BR>

72&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

Get the present state function.<BR>

73&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

<BR>

74&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$state

= $stateTable[$this];<BR>

75&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

<BR>

76&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

Get the next state from this state.<BR>

77&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

<BR>

78&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$next

= &amp;$state($reply);<BR>

79&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printf

&quot;Next state = $next from this state $this\n&quot;;<BR>

80&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

<BR>

81&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

Now advance present state to next state<BR>

82&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#

<BR>

83&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;$this

= $next;<BR>

84&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</FONT></TT>

</BLOCKQUOTE>

<HR>

<P>

Let's see how each function implements the state transitions.

All input into each state consists of removing the initial state

as the first parameter into the subroutine. In Perl, the <TT><FONT FACE="Courier">@_

</FONT></TT>variable is the array of input parameters into a subroutine

and is always defined in each subroutine. In line 37, the <TT><FONT FACE="Courier">shift</FONT></TT>

command forces the first item from the list of input parameters

into <TT><FONT FACE="Courier">$a</FONT></TT>. The value of <TT><FONT FACE="Courier">$a</FONT></TT>

is then used as the current state of the program.

<P>

There are four states in this state machine: <TT><FONT FACE="Courier">S0</FONT></TT>,

<TT><FONT FACE="Courier">S1</FONT></TT>, <TT><FONT FACE="Courier">S2</FONT></TT>,

and <TT><FONT FACE="Courier">S3</FONT></TT>. Each state accepts

input in the form of a number. Each number is used to get the

next state to go to. Note how <TT><FONT FACE="Courier">$a</FONT></TT>

is declared in each state function using the <TT><FONT FACE="Courier">my</FONT></TT>

and <TT><FONT FACE="Courier">local</FONT></TT> types. So if <TT><FONT FACE="Courier">$a</FONT></TT>

has a value of <TT><FONT FACE="Courier">2 </FONT></TT>and receives

an input of <TT><FONT FACE="Courier">3</FONT></TT>, the current

state is <TT><FONT FACE="Courier">2</FONT></TT>, and the program

will do a state transition from <TT><FONT FACE="Courier">2</FONT></TT>

to <TT><FONT FACE="Courier">3</FONT></TT>. After the function

returns, the current state will be <TT><FONT FACE="Courier">3</FONT></TT>.

<P>

Lines 6 through 14 define a subroutine that defines the functionality

of a state. State <TT><FONT FACE="Courier">S0</FONT></TT> transitions

to states <TT><FONT FACE="Courier">S1</FONT></TT> on receiving

a <TT><FONT FACE="Courier">1</FONT></TT>, <TT><FONT FACE="Courier">S2</FONT></TT>

on receiving a <TT><FONT FACE="Courier">2</FONT></TT>, and <TT><FONT FACE="Courier">S3</FONT></TT>

on receiving a <TT><FONT FACE="Courier">3</FONT></TT>. All other

input will not cause a state transition. The other states, <TT><FONT FACE="Courier">{S1,S2,S3}</FONT></TT>,

behave in an analogous way.

<P>

The <TT><FONT FACE="Courier">stateTable</FONT></TT> array is used

to store pointers to each of the functions of the state machine.

The four entries are set in line 49. The initial state is set

to <TT><FONT FACE="Courier">0</FONT></TT>.

<P>

Lines 61 through 84 implement the code for transitioning through

the state machine by accepting input from <TT><FONT FACE="Courier">&lt;STDIN&gt;</FONT></TT>

and calling the present state function to handle the input. Line

74 is where you get the pointer to the function handling all input

for each state in the state machine, and line 78 is where the

state-handling function is called. The next state value returned

by the function is set to the present state (<TT><FONT FACE="Courier">$this</FONT></TT>)

in line 83.

<H2><A NAME="PassingMoreThanOneArrayintoaSubro"><FONT SIZE=5 COLOR=#FF0000>Passing

More Than One Array into a Subroutine</FONT></A></H2>

<P>

Having arrays is great for collecting relevant information. Now

you'll see how to work with multiple arrays via subroutines. Passing

one or more arrays into Perl subroutines is done by reference.

However, you have to keep in mind a few subtle things about using

the <TT><FONT FACE="Courier">@_</FONT></TT> symbol when processing

these arrays in the subroutine. 

<P>

The <TT><FONT FACE="Courier">@_</FONT></TT> symbol is an array

of all the items in a subroutine. So, if you have a call to a

subroutine as follows: 

<BLOCKQUOTE>

<TT><FONT FACE="Courier">$a = 2;<BR>

@b = (&quot;x&quot;,&quot;y&quot;,&quot;z&quot;); <BR>

@c = (&quot;cat&quot;,&quot;mouse&quot;,&quot;chase&quot;); <BR>

&amp;simpleSub($a,@b,@c); </FONT></TT>

</BLOCKQUOTE>

<P>

the <TT><FONT FACE="Courier">@_</FONT></TT> array within the subroutine

will be (<TT><FONT FACE="Courier">2</FONT></TT>, <TT><FONT FACE="Courier">&quot;x&quot;</FONT></TT>,

<TT><FONT FACE="Courier">&quot;y&quot;</FONT></TT>, <TT><FONT FACE="Courier">&quot;z&quot;</FONT></TT>,

 <TT><FONT FACE="Courier">&quot;cat&quot;</FONT></TT>, <TT><FONT FACE="Courier">&quot;mouse&quot;</FONT></TT>,

<TT><FONT FACE="Courier">&quot;chase&quot;</FONT></TT>). That

is, the contents of all the elements will be glued together to

form one long array. 

<P>

Obviously, this ability to glue together arrays will be a problem

to deal with if you want to do operations on two distinct arrays

sequentially. For example, if you have a list of names and a list

of phone numbers, you would want to take the first item from the

names array and the first item from the number array and print

an item. Then take the next name and the next number and print

a combination, and so on. If you pass in the contents of the arrays

to a function that simply uses <TT><FONT FACE="Courier">@_</FONT></TT>,

the subroutine will see one long array, the first half of which

will be a list of strings (names) and the second half of which

will be a list of numbers. 

<P>

The subroutine would have to split the <TT><FONT FACE="Courier">@_</FONT></TT>

in half into two distinct arrays before it can start processing.

The problem gets more complicated if you were to pass three or

four arrays such as those containing items like address and ZIP

code. Now the subroutine will have to manipulate <TT><FONT FACE="Courier">@_

</FONT></TT>even more to get the required number of arrays.

<P>

The simplest way to handle the passing of multiple arrays into

a subroutine is to use references to arrays in the argument list

to the subroutine. That is, you pass in a reference to each array

that the subroutine will be using. The references will be ordered

in the <TT><FONT FACE="Courier">@_</FONT></TT> array within the

subroutine. The code in the subroutine can dereference each item

in the <TT><FONT FACE="Courier">@_</FONT></TT> to the type of

array being referenced. This procedure is known as <I>passing

by reference</I>. The value of what is being referenced can be

changed by the subroutine. When an explicit value is sent to a

subroutine, (that is, you are <I>passing by value</I>), only the

copy of what is sent on the stack is changed, not the actual value.

In Perl, values are passed by reference unless you send in a constant

number. For example, from the following code:

<BLOCKQUOTE>

<TT><FONT FACE="Courier">sub doit {<BR>

$_[0] *= 3.141; <BR>

}<BR>

$\=&quot;\n&quot;; <BR>

$x = 3; <BR>

print $x;<BR>

doit ($x); <BR>

print $x;<BR>

# The following line will cause an error since you will attempt

to <BR>

# modify a read-only value:<BR>

# doit(3);<BR>

</FONT></TT>

</BLOCKQUOTE>

<P>

you will see the following values being printed: 

<BLOCKQUOTE>

<TT><FONT FACE="Courier">3<BR>

9.423</FONT></TT>

</BLOCKQUOTE>

<P>

The second number is the new value of <TT><FONT FACE="Courier">$x</FONT></TT>

after the call to the <TT><FONT FACE="Courier">doit</FONT></TT>

subroutine. Calling the <TT><FONT FACE="Courier">doit</FONT></TT>

subroutine with a constant value such as shown in the commented

lines above will result in an exception with an error message

indicating that your program attempted to modify a read-only value.

The preceeding test confirms that Perl indeed passes values of

variables by reference and not by value. <P>

<CENTER>

<TABLE BORDERCOLOR=#000000 BORDER=1 WIDTH=80%>

<TR VALIGN=TOP><TD ><B>Note</B></TD></TR>

<TR VALIGN=TOP><TD >

<BLOCKQUOTE>

The value of the <TT><FONT FACE="Courier">$\</FONT></TT> system variable is the output separator. In the preceding example, it is set to a newline. By setting the value of <TT><FONT FACE="Courier">$\</FONT></TT> to <TT><FONT FACE="Courier">\n</FONT></TT>, 

the <TT><FONT FACE="Courier">print</FONT></TT> statements did not have to prepend a <TT><FONT FACE="Courier">\n</FONT></TT> to any string being printed. It's a matter of style, of course, and you do not have to use the <TT><FONT 

FACE="Courier">$\</FONT></TT> variable if you do not want to. The default value of this <TT><FONT FACE="Courier">$\</FONT></TT> variable is null. The <TT><FONT FACE="Courier">$\ </FONT></TT>is useful in instances when you are writing special text records 

with the <TT><FONT FACE="Courier">print</FONT></TT> statement that have to have a special record separator such as <TT><FONT FACE="Courier">END\n</FONT></TT> and<TT><FONT FACE="Courier"> RECORDEND\n\n</FONT></TT>.

</BLOCKQUOTE>



</TD></TR>

</TABLE></CENTER>

<P>

<P>

Listing 3.11 provides a sample subroutine that expects a list

of names and a list of phone numbers.

<HR>

<BLOCKQUOTE>

<B>Listing 3.11. Passing multiple arrays into a subroutine.<BR>

</B>

</BLOCKQUOTE>

<BLOCKQUOTE>

<TT><FONT FACE="Courier">&nbsp;1 #!/usr/bin/perl<BR>

&nbsp;2 <BR>

&nbsp;3 @names = (mickey,

goofy, daffy );<BR>

&nbsp;4 @phones = (5551234, 5554321, 666 );<BR>

&nbsp;5 $i = 0;<BR>

&nbsp;6 sub listem {<BR>

&nbsp;7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

my (@a,@b) = @_;<BR>

&nbsp;8&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

foreach (@a) {<BR>

&nbsp;9&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;

print &quot;a[$i] = &quot;. $a[$i] . &quot; &quot; . &quot;\tb[$i]

= &quot; . $b[$i] .&quot;\n&quot;;<BR>

10&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -