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

📄 chapter 11 constructors and destructors.htm

📁 英文版编译器设计:里面详细介绍啦C编译器的设计
💻 HTM
📖 第 1 页 / 共 5 页
字号:
        ; call default constructor for x

        ; do something ...

        ; evaluate some conditional expression here ...
        JZ        __forward_001      ; jump if the condition was false

        LOAD      ERROR_CASE         ; retval = ERROR_CASE
        JMP       __return_exit

      __forward_001:
      
        ; do something else ...
      
        ; evaluate some other conditional expression here ...
        JZ        __forward_002      ; jump if the condition was false
        ; do some special case

        LOAD      SPECIAL_CASE       ; retval = SPECIAL_CASE
        STORE     retval
        JMP       __return_exit

      __forward_002:

        LOAD      GENERAL_CASE       ; retval = GENERAL_CASE
        STORE     retval

      __return_exit:
        ; call destructor of x

        RTN
</PRE>
<P>This is a pretty accurate picture of what the SAL compiler does to insure 
that all destructors get called. Notice that we do not really need a temporary 
variable to store the return value. We can get away with pushing it onto the EES 
and leaving it there. It should be the topmost item when the <TT>RTN</TT> gets 
executed.</P>
<P><!-------------------------------------------------------------------------------->
<H2>11.6 Implementing Constructors and Destructors</H2><!-------------------------------------------------------------------------------->
<H3>11.6.1 Parsing Constructors and Destructors</H3><!-------------------------------------------------------------------------------->Again, 
the parsing for constructors is straightforward. We will modify 
<TT>RuleProcFuncBlock()</TT> in order to achieve the necessary functionality of 
constructors and destructors. 
<MENU><IMG src="Chapter 11 Constructors and Destructors.files/RULE46P.gif">
  <P><FONT face=arial size=-1><B>Figure {RULE46P}</B> </FONT></P></MENU>
<MENU><IMG src="Chapter 11 Constructors and Destructors.files/RULE54P.gif">
  <P><FONT face=arial size=-1><B>Figure {RULE54P}</B> </FONT></P></MENU>
<MENU><IMG src="Chapter 11 Constructors and Destructors.files/RULE55P.gif">
  <P><FONT face=arial size=-1><B>Figure {RULE55P}</B> </FONT></P></MENU>
<MENU><IMG src="Chapter 11 Constructors and Destructors.files/RULE60P.gif">
  <P><FONT face=arial size=-1><B>Figure {RULE60P}</B> </FONT></P></MENU>
<H3>11.6.2 Symbol Tables for Constructors and Destructors</H3><!-------------------------------------------------------------------------------->The 
first modification that we need is to <TT>RuleClassType</TT>. We need to make 
sure that our class has default constructors and destructors if they are needed. 
This checklist will help us decide if we need to generate a default 
constuctor/destructor. If the answer to any of these questions is no, then we do 
not generate a default constuctor/destructor. Although we do not mention 
destructors in the next few paragraphs, all of these rules apply equally and 
without modification. 
<OL>
  <LI>Does our class have no constructors? 
  <LI>Does the class have any base classes? 
  <LI>Do any of the base classes have at least one constructor? 
  <LI>For all base classes with constructors, do all of them have a default 
  constructor (may be in addition to an arbitrary amount of non-default 
  constructors)? </LI></OL>If the answer to the last question is yes, then we 
can/must generate a default constructor. If the answer was no, then we can do 
nothing, and generate an error. The current class needs a constructor of some 
sort, and the compiler has no way to generate a default constructor that can 
call one of the specialized constructors for its base class. By design, a 
non-default constructor was meant to initialize the class in a special, unique 
way. If the class has a non-default constructor and no default constructor, then 
it is impossible for the compiler to know how the class ought to be initialized 
under general circumstances.
<P>In order to perform the above test, we can make use of two Boolean variables. 
One is called <TT>hasCtor</TT>, and the other is called <TT>needsCtor</TT>. Both 
are initialized to <TT>false</TT>. If our class declaration has any constructor, 
then we set <TT>hasCtor</TT> to <TT>true</TT>. If any of our base classes has a 
constructor, then we set <TT>needsCtor</TT> to <TT>true</TT>. This procedure 
takes care of the first three questions. At the end of the class declaration we 
can check these two variables and decide whether or not we need to generate a 
default constructor. 
<MENU>
  <TABLE border=1>
    <TBODY>
    <TR>
      <TH>&nbsp;</TH>
      <TH>hasCtor = <TT>true</TT></TH>
      <TH>hasCtor = <TT>false</TT></TH></TR>
    <TR>
      <TH>needsCtor = <TT>true</TT></TH>
      <TD>Ok. Do nothing</TD>
      <TD>Generate default constructor</TD></TR>
    <TR>
      <TH>needsCtor = <TT>false</TT></TH>
      <TD>Ok. Do nothing</TD>
      <TD>Ok. Do nothing</TD></TR></TBODY></TABLE></MENU>By now, the burning question 
should be, "What about the fourth point"? If there exists a base class with no 
default constructor and at least one non-default constructor, then we should 
signal an error. It turns out that we can (and should) take care of this point 
elsewhere when we process the super statement. This is a more general approach, 
that also takes care of any type of constructor. Again, all of this behavior 
applies equally to destructors. We need to make one additional modification to 
<TT>RuleClassType()</TT> for the benefit of destructors. We need to add code for 
the meta-destructor. Since the code for the meta-destructor and the class 
destructor is one and the same, it is appropriate to mention it at this time.
<P>Figures {RULE12S} and {RULE13S} shows all of the appropriate modifications 
that we need to make.
<P>
<MENU><IMG src="Chapter 11 Constructors and Destructors.files/RULE12S.gif">
  <P><FONT face=arial size=-1><B>Figure {RULE12S}</B> The value, NO_CTOR_NEEDED 
  is a special constant that is used to signal to the compiler that no 
  constructor/destructor is needed for a class. The information in hasCtor and 
  hasDtor should be passed back to RuleClassType().</FONT></P></MENU>
<MENU><IMG src="Chapter 11 Constructors and Destructors.files/RULE13S.gif">
  <P><FONT face=arial size=-1><B>Figure {RULE13S}</B> </FONT></P></MENU>Generating 
a default constructor or default destructor is fairly simple. It involves using 
the token queue, and an additional call to <TT>RuleProcDeclaration()</TT>. 
Notice that the tokens are pushed on in reverse order. This is because we are 
inserting them at the front of the queue. <PRE>      if !hasCtor and needsCtor then
        OutSymbol(constructorsy);
        OutSymbol(endsy);
        OutSymbol(beginsy);
        OutSymbol(semicolonsy);
        OutSymbol(rparentsy);
        OutSymbol(lparentsy);
        OutSymbol(constructorsy);
        ProcFuncDeclaration (lkeys, classblock, FALSE); 
      end if;
      if !hasDtor &amp;&amp; needsDtor then
        OutSymbol(destructorsy);
        OutSymbol(endsy);
        OutSymbol(beginsy);
        OutSymbol(semicolonsy);
        OutSymbol(rparentsy);
        OutSymbol(lparentsy);
        OutSymbol(destructorsy);
        ProcFuncDeclaration (lkeys, classblock, FALSE); 
      end if;
</PRE>By now, the code at the end of <TT>RuleClassType()</TT> should be quite 
confusing. We have listed it here with comments in order to better clarify what 
is happening: <PRE>	//*** parse "end class"
	TestSymbol (endsy, ER_NOEND, keys);
	TestSymbol (classsy, ER_NOQUALIF, keys);

	//*** Check to see that something was actually declared
	if totalsize = 0 then
	   WarningMsg("Size of class is zero or unknown");
	end if;

	//*** Set group properties
	classblock-&gt;setGroupSize (totalsize);					// Groupsize
	classblock-&gt;setSize ( totalsize + classblock-&gt;getSharedSize());		// Total size
	classblock-&gt;setVtblGroupSize(vproccount);				// Vtable group size
	classblock-&gt;AllocateShares();						// Partition group segments
	classblock-&gt;modnum(table.ModNum);					// Set mod # for meta-ctor

	//*** Set  ctorprocnum
	classblock-&gt;setMetaCtorProcNum(++procNum);
	
	//*** Set dtor procnum: dtorident is a FunctionIdent
	dtorident= classblock-&gt;getDestructor();
	if dtorident &lt;&gt;  NO_CTOR_NEEDED and  dtorident &lt;&gt; null then
		classblock-&gt;setMetaDtorProcNum(dtorident-&gt;getProcNum());
	end if;                 

	//*** Set vtableprocnum
	classblock-&gt;setVtblProcNum(++procNum);    

	//*** Tie the class's info to that of the identifier for the class
	classident-&gt;setExtra (classblock);
	
	//*** Create the meta-constructor
	BuildConstructor(classblock);

	//*** Back the table out to the previous scope
	table.Leave_Block();

</PRE>We do a lot of work in <TT>RuleCtorDeclaration()</TT> and 
<TT>RuleDtorDeclaration</TT>. We have to let the containing class know that each 
new procedure is a constructor or destructor, and which constructor is default 
if there is one. Destructors in SAL are virtual by default.
<P>
<MENU><IMG src="Chapter 11 Constructors and Destructors.files/RULE54S.gif">
  <P><FONT face=arial size=-1><B>Figure {RULE54S}</B> </FONT></P></MENU>
<MENU><IMG src="Chapter 11 Constructors and Destructors.files/RULE55S.gif">
  <P><FONT face=arial size=-1><B>Figure {RULE55S}</B> </FONT></P></MENU>The final 
bit of coding for symbol tables is in making the super statement work. The 
approach we will demonstrate here is to utilize the token queue. Our procedure 
works like so: 
<OL>
  <LI>If we are in a class constructor: 
  <OL>
    <LI>Process any super statements, keeping track of which base classes have 
    had a constructor called. We also make sure that the same base class is not 
    constructed twice. 
    <LI>Once all super statements have been processed loop all base classes 
    <I>in their order of declaration</I>. For each base class where a 
    constructor has not been called in the previous step, if the base class has 
    <I>any</I> constructor, call <I>the default constructor</I>. If there is no 
    default constructor, then give an error. The compiler can not know on its 
    own how to call a constructor that takes arguments. The only constructor 
    that can take zero arguments is the default constructor. The default 
    constructor can be called by pushing tokens to make a super statement. 
  </LI></OL>
  <P></P>
  <LI>Process statements, like a normal procedure or function.
  <P></P>
  <LI>If we are in a class destructor: 
  <OL>
    <LI>Process any super statements, keeping track of which base classes have 
    had a destructor called. We also make sure that the same base class is not 
    destructed twice. 
    <LI>Once all super statements have been processed loop all base classes 
    <I>in the opposite order of declaration</I>. For each base class where a 
    destructor has not been called in the previous step, call the destructor. 
    The destructor can be called by pushing tokens for a super statement. 
  </LI></OL>
  <P></P></LI></OL>There exists a function that performs each of these steps. 
There is one for constructors called <TT>CallBaseClassCtors()</TT>, and one for 
destructors called <TT>CallBaseClassDtors()</TT>. These functions also act like 
rules. They work by processing as many super statements as are given, then using 

⌨️ 快捷键说明

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