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

📄 chapter 14 pointers.htm

📁 英文版编译器设计:里面详细介绍啦C编译器的设计
💻 HTM
📖 第 1 页 / 共 3 页
字号:
  can be found by calling <TT>Ident::getSize()</TT>. To simplify the amount of 
  conditions that we will encounter, we can use the <TT>EmitLoad()</TT> function 
  found in <TT>SAL-CodeGen.CPP</TT>. This function covers all four cases of 
  where the variable might be stored and covers any possible size that the 
  variable might be. In all this amounts to sixteen different possiblities. This 
  is the code that we use to generate an rvalue of (i.e., retrieve the value 
  from) a variable:
  <P><PRE>    offset:= ident-&gt;getOffset();
    size:= ident-&gt;getSize();
    level:= ident-&gt;getFuncLevel();
  
    if ident-&gt;getByVal() =  true  then
        if ident-&gt;getMod() &lt;&gt; table.ModNum then    // Variable is external
          EmitLoad( _LE_, size, offset,ident-&gt;mod() );
        else if level = 0 then                              // Variable is global
          EmitLoad( _LG_, size, offset );
        else if table.curFuncLevel() = level then           // Variable is local
          EmitLoad( _LL_, size, offset );
        else                                                // Variable is in parent proc/func
          Emit( xGB, level );
          EmitLoad( _LS_, size, offset );
        end if;
   else
   .... // see pass by ref/pointer below
</PRE>
  <P>We begin by taking the size of the variable and getting its offset. If the 
  variable is external, we use the <TT>_LE_</TT> constant, and pass in the size 
  and offset, and also pass in the module number. The next two cases are 
  virtually the same, with exception to the <TT>_LG_</TT> and <TT>_LL_</TT> 
  values passed in as the first parameter. In the last case, we emit a 
  <TT>GB</TT> instruction, which leaves an address on the stack to a parent 
  function's local variable area. The variable that we want is at an offset from 
  this address. The <TT>LSx</TT> instruction will take an offset as a parameter, 
  and retrieve the value stored at the computed address.
  <P><B>Making an rvalue from a reference.</B> This is the case when a variable 
  has been passed into a function by reference: <PRE>      proc foo(var x: int);

      begin
        write x;
              ^
              |______ Get the value of x and put it on the EES
</PRE>This feat involves dereferencing a pointer. Since a reference can only 
  be found on the local stack, we don't have to worry about global variables or 
  external variables that are references. Only two cases apply. Instead of 
  storing a value, the variable stores a 32-bit pointer. We load the pointer 
  from wherever it is in memory onto the EES, and then tell the VM to load a 
  value at that address. We then dereference the variable pointer if necessary. 
  It is a three-step process.
  <P><PRE>
       ...
    else 
	// step One
	if  ident-&gt;getMod() != table.ModNum   then                     //* External
		Emit( xLED, ident-&gt;getMod(), offset);     
	else if  ident-&gt;getFuncLev() == 0     then                     //* Global
		Emit( xLGD, offset );
	else if  table.curFuncLevel() == ident-&gt;getFuncLev() then      //* Local
		Emit( xLLD, offset );
	else                                                              //* Base
		Emit( xGB, GBLevel(ident) );
		Emit( xLSD, offset );
	end if;

	//step Two
 	EmitLoad( _LS_, Size, 0 );
    end if;
   
    <FONT color=green>
     // dereference the	variable needed 
     //	step  Three      
     if deref  then 
	for(x = 1; x &lt; deref; x++)
		   Emit(xLSD, 0); 
	x := GET_TYPE_BYTE_SIZE(ident-&gt;getSubtype());
	if x=0 then  x: = 4; end if;
	EmitLoad( _LS_, x,0);
     end if; 
    </FONT>

</PRE>In step one, the first condition loads a dword at the offset from L. The 
  second condition computes a parent's base address, and then loads a dword at 
  an offset from that. In step two, the address that we now have on the EES is 
  used to fetch the actual value.
  <P><B>Making an lvalue from a variable.</B> This is a simpler operation. All 
  we need is to load the address to the variable onto the EES. We will use one 
  of the four instructions, <TT>LGA</TT>, <TT>LLA</TT>, <TT>LEA</TT>, or 
  <TT>LSA</TT> for computing addresses. All we need to know is the area where 
  the variable is stored, and the offset from the starting point of the area. 
  Again, the location is going to be either the global data area, the local 
  stack, an external module, or in a parent scope.
  <P><PRE>      level  := ident-&gt;getFuncLevel();
      offset := ident-&gt;getOffset() 
       
      if ident-&gt;getByVal() =  true  <FONT color=green>&amp;&amp; deref = 0</FONT> then 
       
        if ident-&gt;getMod() &lt;&gt; table.ModNum then    // Variable is external
          Emit( LEA,ident-&gt;getMod(), offset );
        else if level = 0 then                              // Variable is global
          Emit( xLGA, offset );
        else if table.curFuncLevel() = level then           // Variable is local
          Emit( xLLA, offset );
        else                                                // Variable is in parent proc/func
          Emit( xGB, level );
          Emit( xLSA, offset );
        end if;
      else
      . . .  // continued below
</PRE><B>Making an lvalue from a reference.</B> This is the simplest case, 
  since a reference and an lvalue are both a pointer. As always, references are 
  stored on the local stack or in a parent procedure's local stack frame. We use 
  the <TT>LLD</TT> or <TT>LSD</TT> instructions (Load Local Dword and Load Stack 
  Dword) to load the variables address from where it is stored, and we are done. 
<PRE>      . . . // continued from above
     
      else<FONT color=green>
        if ident-&gt;getByVal() &amp;&amp; deref then // adjust pointer level for pass by reference       
            deref--;
        end if; </FONT>
        if ident-&gt;getMod() &lt;&gt; table.ModNum then         	         //* External 
		Emit(xLED, ident-&gt;getMod(),offset);
        else  ifident-&gt;getFuncLev() == 0     then                     //* Global
		Emit( xLGD, offset );
	else if  table.curFuncLevel() == ident-&gt;getFuncLev() then     //* Local
		Emit( xLLD, offset );
	else                                                             //* Base
		Emit( xGB, GBLevel(ident) );
		Emit( xLSD, offset );
	end if;
      <FONT color=green>
        for( ; deref; deref--)               // dereference pointers
          Emit(xLSD, 0);
                         </FONT>
      end if;

</PRE>Notice the similarity between this and the code to load the value of a 
  reference. The only thing not done in this case is the call to emit an 
  additional <TT>LSx</TT>
  <P></P></MENU>
<P>
<H3>14.6.3 Complex Types <FONT color=green>(NEW)</FONT> </H3>As we did in the 
431 compiler whenever we encountered a variable of a complex type, we emitted a 
base address first. We must also be able to handle the cases where the variable 
is a pointer to a complex type. <BR>Here is an example <PRE>   type Rec is record;
       i:int;
   end record;
   
   var  recPtr: ^Rec;
        recPtrPtr: ^^Rec;
        y: int;
   begin
        // initializations here
        recPtrPtr^ := new(Rec);
        y:=recPtr^.i;
        recPtr:= recPtrPtr^;
        y:=recPtrPtr^.i; // not legal
        ...
</PRE>We must output the correct stuff here <PRE>     <FONT color=green>
     if (!makerval &amp;&amp; rval-&gt;getPlev() &amp;&amp; !deref &amp;&amp; token.sy&lt;&gt;lbracksy &amp;&amp; ident-&gt;getByVal()) then // a reference		
        if ident-&gt;getMod() &lt;&gt; table.ModNum then    // Variable is external
          Emit( LEA,ident-&gt;getMod(), offset );
        else if level = 0 then                              // Variable is global
          Emit( xLGA, offset );
        else if table.curFuncLevel() = level then           // Variable is local
          Emit( xLLA, offset );
        else                                                // Variable is in parent proc/func
          Emit( xGB, level );
          Emit( xLSA, offset );
        end if;
</FONT>		
    else
       // emit base address.....
    end if;
     <FONT color=green>
	//  after emitting base address
	if makerval then
		if ident-&gt;getPlev() &amp;&amp; !ident-&gt;getByVal() then
			Emit(xLSD, 0);
		end if;
		if ident-&gt;getPlev()&gt;1 &amp;&amp; deref then
	 		BYTE x := (BYTE)deref;
			if  x= ident-&gt;getPlev() then
			  x--;
			end if; 
			while x-- do 
		 		Emit(xLSD, 0);
              		loop;

		end if;
	else if deref then
	
                if ident-&gt;getByVal() then
			deref--;
        	end if;
	
        while deref-- do
		Emit(xLSD, 0);
	loop;
    end if;
</FONT>
</PRE>Before we make a call to rule designator, we must be sure that the record 
is completely dereferenced. That is why when we determined that the identifier 
was a variable, we calculated its current pointer level. So we need to change 
the code just before RuleDesignator as follows: <PRE>    else if rval-&gt;isComplexType()&amp;&amp; TestToken(FirstDesignator) then if
         (currPtrLevel &lt;&gt;  0) then
            SemanticErrorMsg("Whatever error message you want");
         end if;
         RuleDesignator(follow, last, ident, rval, makerval);
    else
    ... </PRE>
<H3>14.6.4 Function Calls and TypeCasting <FONT color=green>(NEW)</FONT> 
</H3>When we make a function call or a type cast we may want to dereference the 
return. for example: <PRE> i: int;
 i:= returnsIntPointer()^;
 </PRE>So, In RuleIdentExpression we should insert the code after 
ruleprocfunccall and RuleTypeConvert to dereference the pointer if needed. We 
can do this by calling GetPointerLevel and emitting xLSD's for multiple pointer 
levels and completely dereference the simple types. <BR>We can use a helper 
procedure such as below: <PRE>void ParserPointers::DereferencePointer(Set follow, Symbol last, Type *rtype, BOOLEAN MakeRValue) 
var
	deref    : BYTE;
	origplev : BYTE; 
begin       
        origplev :=0;
	deref    := RuleGetPointerLevel(follow, last);
	
        if deref &lt;&gt; 0 then
		if(deref &gt; rtype-&gt;getPlev()) then
			SemanticErrorMsg("Pointer error");
 		end if;
                origplev = rtype-&gt;getPlev();
		rtype-&gt;setPlev(origplev-deref);
	end if;
	
	if !MakeRValue then                  
		if rtype-&gt;IsSimpleType() &amp;&amp; !deref  then
	                SemanticErrorMsg("Cannot return an lvalue of this type");
		else if !rtype-&gt;IsSimpleType() &amp;&amp; !origplev then
			WarningMsg("Temporary used as lvalue");
                end if;
	end if;
	
	if deref then
		if (deref==origplev || !MakeRValue || rtype-&gt;IsComplexType()) then
			deref--;
          	end if;
		while (deref--) do
 			Emit(xLSD, 0);
		loop;

		//* Do this if a simple type is completely dereferenced, and rvalue is required
		if MakeRValue &amp;&amp; origplev &amp;&amp; !rtype-&gt;getPlev() &amp;&amp; rtype-&gt;IsSimpleType() then
			EmitLoad(_LS_, GET_TYPE_BYTE_SIZE(rtype-&gt;getSubtype()), 0);
	        end if;
	end if;
end;
</PRE>
<P>Using such a procedure, we can minimize our change to RuleIdentExpression to 
as follows:</P><PRE>  else if ident-&gt;obj = typeobj then
      RuleTypeConvert( local+follow, RType);
      <FONT color=green>if token.sy == pointersy then 
           DereferencePointer(follow, last, rval, makerval); 
      end if;</FONT>

  else if ident-&gt;obj =  funcobj orident-&gt;obj = procobj then
      RuleProcFuncCall();
     <FONT color=green>if token.sy == pointersy then 
           DereferencePointer(follow, last, rval, makerval); 
      end if;</FONT>
</PRE>
<H3>14.6.5 The Ampersand '&amp;' </H3>
<P>If you encounter an ampersand, you treat the indentifier as an lvalue. You do 
this by setting makerval to false. You also need to increment the rype's plev by 
one. You don't want to do this right away at the beginning because it will mess 

⌨️ 快捷键说明

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