📄 ch18_07.htm
字号:
<html><head><title>Avant-Garde Compiler, Retro Interpreter (Programming Perl)</title><!-- STYLESHEET --><link rel="stylesheet" type="text/css" href="../style/style1.css"><!-- METADATA --><!--Dublin Core Metadata--><meta name="DC.Creator" content=""><meta name="DC.Date" content=""><meta name="DC.Format" content="text/xml" scheme="MIME"><meta name="DC.Generator" content="XSLT stylesheet, xt by James Clark"><meta name="DC.Identifier" content=""><meta name="DC.Language" content="en-US"><meta name="DC.Publisher" content="O'Reilly & Associates, Inc."><meta name="DC.Source" content="" scheme="ISBN"><meta name="DC.Subject.Keyword" content=""><meta name="DC.Title" content="Avant-Garde Compiler, Retro Interpreter"><meta name="DC.Type" content="Text.Monograph"></head><body><!-- START OF BODY --><!-- TOP BANNER --><img src="gifs/smbanner.gif" usemap="#banner-map" border="0" alt="Book Home"><map name="banner-map"><AREA SHAPE="RECT" COORDS="0,0,466,71" HREF="index.htm" ALT="Programming Perl"><AREA SHAPE="RECT" COORDS="467,0,514,18" HREF="jobjects/fsearch.htm" ALT="Search this book"></map><!-- TOP NAV BAR --><div class="navbar"><table width="515" border="0"><tr><td align="left" valign="top" width="172"><a href="ch18_06.htm"><img src="../gifs/txtpreva.gif" alt="Previous" border="0"></a></td><td align="center" valign="top" width="171"><a href="ch18_01.htm">Chapter 18: Compiling</a></td><td align="right" valign="top" width="172"><a href="ch19_01.htm"><img src="../gifs/txtnexta.gif" alt="Next" border="0"></a></td></tr></table></div><hr width="515" align="left"><!-- SECTION BODY --><h2 class="sect1">18.7. Avant-Garde Compiler, Retro Interpreter</h2><p><a name="INDEX-3304"></a><a name="INDEX-3305"></a>There's a right time to think about everything; sometimes that time isbeforehand, and sometimes it's after. Sometimes it's somewhere in the middle.Perl doesn't presume to know when it's the right time to think,so it gives the programmer a number of options for telling it when to think.Other times it knows that some sort of thinking is necessary but doesn'thave any idea what it ought to think, so it needs ways of asking your program.Your program answers these kinds of questions by defining subroutineswith names appropriate to what Perl is trying to find out.</p><p><a name="INDEX-3306"></a>Not only can the compiler call into the interpreter when it wants tobe forward thinking, but the interpreter can also call back to thecompiler when it wants to revise history. Your program can use severaloperators to call back into the compiler. Like the compiler, theinterpreter can also call into named subroutines when it wants to findthings out. Because of all this give and take between the compiler,the interpreter, and your program, you need to be aware of what thingshappen when. First we'll talk about when these named subroutines aretriggered.</p><p>In <a href="ch10_01.htm">Chapter 10, "Packages"</a>, we saw how a package's<tt class="literal">AUTOLOAD</tt> subroutine is triggered when an undefinedfunction in that package is called. In<a href="ch12_01.htm">Chapter 12, "Objects"</a>, we met the <tt class="literal">DESTROY</tt>method which is invoked when an object's memory is about to beautomatically reclaimed by Perl. And in<a href="ch14_01.htm">Chapter 14, "Tied Variables"</a>, we encountered the manyfunctions implicitly called when a tied variable is accessed.</p><p><a name="INDEX-3307"></a><a name="INDEX-3308"></a><a name="INDEX-3309"></a><a name="INDEX-3310"></a>These subroutines all follow the convention that, if a subroutine is triggeredautomatically by either the compiler or the interpreter, we write itsname in uppercase. Associated with the different stages of yourprogram's lifetime are four other such subroutines, named <tt class="literal">BEGIN</tt>,<tt class="literal">CHECK</tt>, <tt class="literal">INIT</tt>, and <tt class="literal">END</tt>. The <tt class="literal">sub</tt> keyword is optional beforetheir declarations. Perhaps they are better called "blocks", becausethey're in some ways more like named blocks than real subroutines.</p><p>For instance, unlike regular subroutines, there's no harm in declaringthese blocks multiple times, since Perl keeps track of when to callthem, so you never have to call them by name. (They are also unlikeregular subroutines in that <tt class="literal">shift</tt> and <tt class="literal">pop</tt> act as though you werein the main program, and so they act on <tt class="literal">@ARGV</tt> by default, not <tt class="literal">@_</tt>.)</p><p>These four block types run in this order:</p><dl><dt><b><tt class="literal">BEGIN</tt></b></dt><dd><p>Runs ASAP (as soon as parsed) whenever encountered duringcompilation, before compiling the rest of the file.</p></dd><dt><b><tt class="literal">CHECK</tt></b></dt><dd><p>Runs when compilation is complete, but before the programstarts. (<tt class="literal">CHECK</tt> can mean "checkpoint" or "double-check" or even just "stop".)</p></dd><dt><b><tt class="literal">INIT</tt></b></dt><dd><p>Runs at the beginning of execution right before the main flow of yourprogram starts.</p></dd><dt><b><tt class="literal">END</tt></b></dt><dd><p>Runs at the end of execution right after the program finishes.</p></dd></dl><p></p><p>If you declare more than one of these by the same name, even inseparate modules, the <tt class="literal">BEGIN</tt>s all run before any <tt class="literal">CHECK</tt>s, whichall run before any <tt class="literal">INIT</tt>s, which all run before any <tt class="literal">END</tt>s--whichall run dead last, after your main program has finished. Multiple<tt class="literal">BEGIN</tt>s and <tt class="literal">INIT</tt>s run in declaration order (FIFO), and the<tt class="literal">CHECK</tt>s and <tt class="literal">END</tt>s run in inverse declaration order (LIFO).</p><p>This is probably easiest to see in a demo:<blockquote><pre class="programlisting">#!/usr/bin/perl -lprint "start main running here";die "main now dying here\n";die "XXX: not reached\n";END { print "1st END: done running" }CHECK { print "1st CHECK: done compiling" }INIT { print "1st INIT: started running" }END { print "2nd END: done running" }BEGIN { print "1st BEGIN: still compiling" }INIT { print "2nd INIT: started running" }BEGIN { print "2nd BEGIN: still compiling" }CHECK { print "2nd CHECK: done compiling" }END { print "3rd END: done running" }</pre></blockquote>When run, that demo program produces this output:<blockquote><pre class="programlisting">1st BEGIN: still compiling2nd BEGIN: still compiling2nd CHECK: done compiling1st CHECK: done compiling1st INIT: started running2nd INIT: started runningstart main running heremain now dying here3rd END: done running2nd END: done running1st END: done running</pre></blockquote><a name="INDEX-3311"></a>Because a <tt class="literal">BEGIN</tt> block executes immediately, it can pull insubroutine declarations, definitions, and importations before the restof the file is even compiled. These can alter how the compiler parsesthe rest of the current file, particularly if you import subroutinedefinitions. At the very least, declaring a subroutine lets it be usedas a list operator, making parentheses optional. If the importedsubroutine is declared with a prototype, calls to it can be parsed likebuilt-ins and can even override built-ins of the same name in order togive them different semantics. The <tt class="literal">use</tt> declaration is just a<tt class="literal">BEGIN</tt> block with an attitude.</p><p><a name="INDEX-3312"></a><tt class="literal">END</tt> blocks, by contrast, are executed as<em class="emphasis">late</em> as possible: when your program exits thePerl interpreter, even if as a result of an untrapped<tt class="literal">die</tt> or other fatal exception. There are twosituations in which an <tt class="literal">END</tt> block (or a<tt class="literal">DESTROY</tt> method) is skipped. It isn't run if,instead of exiting, the current process just morphs itself from oneprogram to another via <tt class="literal">exec</tt>. A process blown outof the water by an uncaught signal also skips its<tt class="literal">END</tt> routines. (See the <tt class="literal">usesigtrap</tt> pragma described in <a href="ch31_01.htm">Chapter 31, "Pragmatic Modules"</a>, for an easy way to convertcatchable signals into exceptions. For general information on signalhandling, see "Signals" in <a href="ch16_01.htm">Chapter 16, "Interprocess Communication"</a>.) To avoid all<tt class="literal">END</tt> processing, you can call<tt class="literal">POSIX::_exit</tt>, say <tt class="literal">kill -9, $$</tt>,or just <tt class="literal">exec</tt> any innocuous program, such as<em class="emphasis">/bin/true</em> on Unix systems.</p><p><a name="INDEX-3313"></a>Inside an <tt class="literal">END</tt> block, <tt class="literal">$?</tt> contains the status the program is goingto <tt class="literal">exit</tt> with. You can modify <tt class="literal">$?</tt> from within the <tt class="literal">END</tt> block tochange the exit value of the program. Beware of changing <tt class="literal">$?</tt>accidentally by running another program with <tt class="literal">system</tt> or backticks.</p><p>If you have several <tt class="literal">END</tt> blocks within a file, theyexecute in <em class="emphasis">reverse</em> order of their definition.That is, the last <tt class="literal">END</tt> block defined is the firstone executed when your program finishes. This reversal enablesrelated <tt class="literal">BEGIN</tt> and <tt class="literal">END</tt> blocks tonest the way you'd expect, if you pair them up. For example, if themain program and a module it loads both have their own paired<tt class="literal">BEGIN</tt> and <tt class="literal">END</tt> subroutines, likeso:<blockquote><pre class="programlisting">BEGIN { print "main begun" }END { print "main ended" }use Module;</pre></blockquote>and in that module, these declarations:<blockquote><pre class="programlisting">BEGIN { print "module begun" }END { print "module ended" }</pre></blockquote>then the main program knows that its <tt class="literal">BEGIN</tt> willalways happen first, and its <tt class="literal">END</tt> will always happenlast. (Yes, <tt class="literal">BEGIN</tt> is really a compile-time block,but similar arguments apply to paired <tt class="literal">INIT</tt> and<tt class="literal">END</tt> blocks at run time.) This principle isrecursively true for any file that includes another when both havedeclarations like these. This nesting property makes these blockswork well as package constructors and destructors. Each module canhave its own set-up and tear-down functions that Perl will callautomatically. This way the programmer doesn't have to remember thatif a particular library is used, what special initialization orclean-up code ought to be invoked, and when. The module'sdeclarations assure these events.</p><p>If you think of an <tt class="literal">eval</tt><em class="replaceable">STRING</em> as a call <em class="emphasis">back</em> from theinterpreter to the compiler, then you might think of a <tt class="literal">BEGIN</tt> as acall <em class="emphasis">forward</em> from the compiler into the interpreter. Bothtemporarily put the current activity on hold and switch modes ofoperation. When we say that a <tt class="literal">BEGIN</tt> block is executed as early aspossible, we mean it's executed just as soon as it is completelydefined, even before the rest of the containing file is parsed.<tt class="literal">BEGIN</tt> blocks are therefore executed during compile time, never
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -