📄 chapter 14 pointers.htm
字号:
up your plev checks within rule ident expression. If there is an ampersand you
can set a boolean flag and at the very end of ruleIdentExpr if that flag is set
increment rtype's plev. </P>
<H3>14.6.5 Summary of <TT>RuleIdentExpr()</TT></H3><!-----------------------------------------------------------------------------><PRE>In just a recap, we have talked about how <TT>RuleIdentExpr()</TT> operates. This rule operates
on anything in SAL that is an identifier. For the most part it generates rvalues, however, it
can also generate lvalues with variables. The flag, <TT>MakeRValue</TT> tells it which case
it needs to do. If <TT>RuleIdentExpr()</TT> is told to make an lvalue from a constant or a
type conversion, then it should report an error (don't eat tokens, just report an error).</PRE><PRE>
This rule also has an in/out parameter that is used for resolving constant types. If possible,
the constant should be matched as closely as possible to the type that is passed in. The rule
should then choose a final type and then return that to the caller. <TT>RuleIdentExpr()</TT>
also takes a sign parameter that is useful for setting the sign. This is also used in setting
the final constant's type.</PRE><PRE>
In all cases, the <TT>RType</TT> (return type) should be set to whatever the ident's type turned
out to be. In any event, the skeleton code for <TT>RuleIdentExpr()</TT> would look like this:
</PRE><PRE>var
Ident *ident;
begin
ident:= RuleQualIdent ( local+follow );
if ident = null then
RType.Init(notyp,nosubtyp);
return;
else if ident->obj<> constobj then
RType.Init(ident);
end if;
if ident->obj = constobj then
if MakeRValue = false
then Error: "Can't take lvalue of a constant"
end if
//*** Generate a constant based on RType's setings and the
//*** value in Sign (Set Sign to zero afterwards).
else if ident->obj = varobj
then ifrval->isComplexType()
// handle records/arrays/classes
else if MakeRValue then
//*** Make an rvalue
else
//*** Make an lvalue
end if;
else if ident->obj = typeobj then
RuleTypeConvert( local+follow, RType);
if MakeRValue = false
then Error: "Can't take lvalue of a type-conversion"
endif;
// Dereference Pointers
else if ident->obj = funcobj orident->obj = procobj then
RuleProcFuncCall();
// Dereference Pointers
end if;
</PRE>
<H2>14.7 RuleDesignator</H2>Once again to make a long story short, we have to
handle Rec.field^^^ and arr[5]^^^ and the like. We do this in rule designator
like this: <PRE>
do {
Check(local+follow, "Designator expected");
....
<FONT color=green>deref = RuleGetPointerLevel(follow, last);
if (deref) {
if(deref > rval->getPlev())
SemanticErrorMsg("Pointer error");
rval->setPlev(rval->getPlev() - deref);
while(deref--) {
Emit(xLSD, 0);
}
</FONT>
}
} while (TestToken(FirstMemberField) || TestToken(FirstArrayIndexing) );
if (makerval && !procFuncCall) { //* resolve lvalue to an rvalue
<FONT color=green>if(rval->getPlev())
Emit(xLSD, 0); </FONT>
else if (rval->IsSimpleType())
EmitLoad(_LS_, GET_TYPE_BYTE_SIZE(rval->subtype) , 0);
}
</PRE>
<H2>14.8 RuleCmpExpr</H2>Do determine whether a pointer is null or if two
pointers are the same, we need to be able to compare pointers. This entails some
adjusting to RuleCmpExpression. In it when we out put the code for a comparison
if what we are comparing is pointers, we need to do the right size
comparison.<BR>To make a long story short here are the changes that need to be
made: <PRE> <FONT color=green>if(rtype->getPlev()) {
Emit (xUCMPD);
} else </FONT> if(rtype->type == booltyp)
{ Emit(xUCMPB); }
else if(rtype->type == realtyp){
Emit(xFCMP_ + subtype);
} else if(rtype->type == inttyp) {
Emit(xCMP_ + subtype);
</PRE>
<H2>14.9 Memory Management</H2>There eventually will be some theory here, but
for now, here is how you implement Rules new and delete<PRE></PRE></FONT>
<H3>14.9.1 New </H3>
<P>The basic idea for Rule new is that it is an intrinsic function that
takes a type as a parameter and allocates the size of the type on the heap and
returns the pointer to that allocated area. This is simply done by getting the
size of the type passed in by parameter and calling the VM syscall MALLOC. This
instruction allocates the specified amount of memory on the heap and leaves a 4
byte pointer on the stack to that allocated memory. Actually this chapter
normally comes before the classes chapter, so you would not need to worry about
classes and meta-constructors, but you do here. So, make sure if the type needs
to have the meta constructor called, call it. You can implement new like
follows: </P><PRE>
void Parser531::RuleNew(Set &follow, Type* rtype)
var
Token la;
bool dummy := true;
Ident *temp;
Type ptyp;
Set local (FirstExpression + commasy + scopesy + rparentsy);
begin
LookAhead(la);
if la.sy = atsy then
la := token;
Accept( identsy, follow + atsy + scopesy + commasy, "Missing type identifier");
NextToken();
if token.sy = identsy then
temp := table.findInModule( la.data.id, token.data.id);
else
temp := table.findInModule( la.data.id);
end if;
if temp = NULL || temp->getObj() <> typeobj then
SemanticErrorMsg( "Invalid or undeclared type");
end if;
Accept( identsy, follow + scopesy + commasy, "Missing module identifier");
else
if token.sy = identsy then
temp := table.getCurrentBlock()->Find_Backward( token.data.id, dummy, true);
end if;
if temp = NULL || temp->getObj() <> typeobj then
SemanticErrorMsg( "Invalid or undeclared type");
end if;
Accept( identsy, follow + scopesy + commasy, "Missing type identifier");
end if;
if temp = NULL then
return;
end if;
ptyp.Init( cardtyp, _u32s);
Emit( xLID, temp->getSize());
if temp->getExtra() && temp->getExtra()->getMetaCtorProcNum() then
Check( follow + rparentsy + commasy + scopesy + FirstExpression, "Syntax Error");
if temp->getType()->getType() = classtyp then
Emit( xSYS, 0x04, MALLOC);
Emit( xCOPT, 4);
Check( local + follow, "Syntax Error");
if token.sy = scopesy then
Emit( xCOPT, 4);
NewonItem( temp, FALSE);
NextToken();
Ident *cons := NULL;
if token.sy = identsy && temp->getExtra() && temp->getExtra()->toClassBlock() then
cons := temp->getExtra()->toClassBlock()->GetAMember( token.data.id);
end if;
NextToken();
if !cons || !cons->toFunctionIdent() || ! cons->toFunctionIdent()->getIsConstructor() then
SemanticErrorMsg( "Invalid or missing constructor name");
else
Type temp := *(cons->getType());
Type temp2 := *(cons->getType());
RuleProcFuncCall(follow + rparentsy, lparentsy, cons, &temp, &temp);
end if;
else
NewonItem( temp, TRUE);
end if;
else
Emit( xSYS, 0x04, MALLOC);
Emit( xCOPT, 4);
NewonItem( temp, TRUE);
end if;
else
if temp->getType()->getType() == proctyp || temp->getType()->getType() == functyp then
SemanticErrorMsg( "Cannot allocate memory for procedures and functions");
else
Emit( xSYS, 0x04, MALLOC); // Allocate memory for simple types
end if;
end if;
rtype->Init(temp);
rtype->setPlev(++(rtype->getPlev()));
endif;
end;
</PRE>
<H3>14.9.2 Delete</H3>
<P></P>Delete is pretty similar, but it takes a variable as a parameter and
issues a FREE SYS call, to free the memory. And for later if we are destryoing a
class we need to call the correct destructor if it exists. <BR>You can implement
rule delete like follows:
<P></P><PRE>void Parser531::RuleDelete(Set &follow, Type* rtype)
var
int sign := 0;
begin
RuleIdentExpr( follow + rparentsy, lparentsy, rtype, true, sign);
if rtype->getPlev() < 1 then
SemanticErrorMsg( "Can only delete pointers");
end if;
Emit( xCOPT, 4);
if rtype->getExtra() && rtype->getExtra()->getMetaDtorProcNum() then
Emit( xCOPT, 4);
DeleteItem( rtype->getExtra()->getParent());
// If we are destroying a class, we need to find out if our
// pointer references the whole class, and not a base class.
if rtype->getType() = classtyp && rtype->getPlev() then // If this is a class
ClassBlock *cblock := rtype->getExtra()->toClassBlock();
FunctionIdent *dident := cblock->getDestructor();
if dident && // If this class has a destructor
dident->isVirtualFunc() then // And finally, if this class's destructor is virtual
DWORD vprocnum =: dident->getVProcNum();
Emit (xCOPT, 4); // Copy the pointer to self
Emit (xLSD, 0); // Load the vtable pointer (always at offset 0).
Emit (xLID, 0xFFFFFFFF); // if (*vtable == 0xFFFFFFFF) goto Skip; (Class has no virtual functions).
Emit (xUCMPD);
Emit1(xJPZ);
DWORD Skip := ForwardJump();
Emit (xCOPT, 4); // Copy the pointer to self
Emit (xLSD, 0); // Load the vtable pointer (always at offset 0).
Emit (xLSD, vprocnum*8 + 4); // Get the self fixup.
Emit (xADDD); // Add the two
JumpFix(Skip); // Skip:
end if;
end if;
end if;
Emit( xSYS, 0x04, MFREE);
Emit( xLID, 0);
Emit( xSSD, 0);
rtype->Init( proctyp, nosubtyp);
end;
</PRE>
<H2>14.10</H2>In init vars remember you do not call the meta constructor on a
variable if it is a pointer. </BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -