Tải bản đầy đủ - 0 (trang)
12 HLA's " _initialize_ " and " _finalize_ " Strings

12 HLA's " _initialize_ " and " _finalize_ " Strings

Tải bản đầy đủ - 0trang

unlessyouexplicitlymodifythevalueof_initialize_priortothe

beginclauseoryoumodify_finalize_priortotheendclauseofthe

procedure.Soifyoumodifyeitherofthesestringobjectstocontaina

machineinstruction,HLAwillcompilethatinstructionatthebeginningor

endoftheprocedure.Thefollowingexampledemonstrateshowtouse

thistechnique:

procedureSomeProc;

?_initialize_:="mov(0,eax);";

?_finalize_:="stdout.put(eax);"

beginSomeProc;



//HLAemits"mov(0,eax);"hereinresponsetothe_ini

//stringconstant.

add(5,eax);

//HLAemits"stdout.put(eax);"here.

endSomeProc;

Ofcourse,theseexamplesdon'tsaveyoumuch.Itwouldbeeasierto

typetheactualstatementsatthebeginningandendoftheprocedure

thanassignastringcontainingthesestatementstothe_initialize_

and_finalize_compiletimevariables.However,ifwecouldautomate

theassignmentofsomestringtothesevariables,sothatyoudon'thave

toexplicitlyassignthemineachprocedure,thenthisfeaturemightbe

useful.Inamoment,you'llseehowwecanautomatetheassignmentof

valuestothe_initialize_and_finalize_strings.Forthetime

being,considerthecasewhereweloadthenameofaconstructorinto

the_initialize_stringandweloadthenameofadestructorintothe

_finalize_string.Bydoingthis,theroutinewill"automatically"callthe

constructoranddestructorforthatparticularobject.

Thepreviousexamplehasaminorproblem.Ifwecanautomatethe

assignmentofsomevalueto_initialize_or_finalize_,what

happensifthesevariablesalreadycontainsomevalue?Forexample,

supposewehavetwoobjectsweuseinaroutine,andthefirstoneloads



thenameofitsconstructorintothe_initialize_string;whathappens

whenthesecondobjectattemptstodothesamething?Thesolutionis

simple:Don'tdirectlyassignanystringtothe_initialize_or

_finalize_compiletimevariables;instead,alwaysconcatenateyour

stringstotheendoftheexistingstringinthesevariables.Thefollowingis

amodificationtotheaboveexamplethatdemonstrateshowtodothis:

procedureSomeProc;

?_initialize_:=_initialize_+"mov(0,eax);";

?_finalize_:=_finalize_+"stdout.put(eax);"

beginSomeProc;



//HLAemits"mov(0,eax);"hereinresponsetothe_ini

//stringconstant.

add(5,eax);

//HLAemits"stdout.put(eax);"here.

endSomeProc;

Whenyouassignvaluestothe_initialize_and_finalize_

strings,HLAalmostguaranteesthatthe_initialize_sequencewill

executeuponentryintotheroutine.Sadly,thesameisnottrueforthe

_finalize_stringuponexit.HLAsimplyemitsthecodeforthe

_finalize_stringattheendoftheroutine,immediatelybeforethe

codethatcleansuptheactivationrecordandreturns.Unfortunately,

"fallingofftheendoftheroutine"isnottheonlywaythatonecouldreturn

fromthatroutine.Onecouldexplicitlyreturnfromsomewhereinthe

middleofthecodebyexecutingaretinstruction.BecauseHLAonly

emitsthe_finalize_stringattheveryendoftheroutine,returning

fromthatroutineinthismannerbypassesthe_finalize_code.

Unfortunately,otherthanmanuallyemittingthe_finalize_code,there

isnothingyoucandoaboutthis.[10]Fortunately,thismechanismfor

exitingaroutineiscompletelyunderyourcontrol;ifyouneverexita

routineexceptby"fallingofftheend"thenyouwon'thavetoworryabout

thisproblem(notethatyoucanusetheexitcontrolstructuretotransfer



controltotheendofaroutineifyoureallywanttoreturnfromthatroutine

fromsomewhereinthemiddleofthecode).



Anotherwaytoprematurelyexitaroutine,overwhich,unfortunately,you

don'thaveanycontrol,isbyraisinganexception.Yourroutinecouldcall

someotherroutine(e.g.,aStandardLibraryroutine)thatraisesan

exceptionandthentransferscontrolimmediatelytowhomevercalled

yourroutine.Fortunately,youcaneasilytrapandhandleexceptionsby

puttingatry..endtryblockinyourprocedure.Hereisanexamplethat

demonstratesthis:

procedureSomeProc;

<>

beginSomeProc;



<>

try//Catchanyexceptionsthatoccur:

<>

anyexception



push(eax);//Savetheexception#.

@text(_finalize_);//Executethe_finalize_codeh

pop(eax);//Restoretheexception#.

raise(eax);//Reraisetheexception.

endtry;

//HLAautomaticallyemitsthe_finalize_codehere.

endSomeProc;

Althoughthepreviouscodehandlessomeproblemsthatexistwith

_finalize_,bynomeansdoesithandleeverypossiblecase.Always

beonthelookoutforwaysyourprogramcouldinadvertentlyexita

routinewithoutexecutingthecodefoundinthe_finalize_string.You



shouldexplicitlyexpand_finalize_ifyouencountersuchasituation.

Thereisoneimportantplaceyoucangetintotroublewithrespectto

exceptions:withinthecodetheroutineemitsforthe_initialize_

string.Ifyoumodifythe_initialize_stringsothatitcontainsa

constructorcallandtheexecutionofthatconstructorraisesanexception,

thiswillprobablyforceanexitfromthatroutinewithoutexecutingthe

corresponding_finalize_code.Youcouldburythetry..endtry

statementdirectlyintothe_initialize_and_finalize_strings,but

thisapproachhasseveralproblems,nottheleastofwhichisthefactthat

oneofthefirstconstructorsyoucallmightraiseanexceptionthat

transferscontroltotheexceptionhandlerthatcallsthedestructorsforall

objectsinthatroutine(includingthoseobjectswhoseconstructorsyou

haveyettocall).Althoughnosinglesolutionthathandlesallproblems

exists,probablythebestapproachistoputatry..endtryblockwithin

eachconstructorcallifitispossibleforthatconstructortoraisesome

exceptionthatispossibletohandle(i.e.,doesn'trequiretheimmediate

terminationoftheprogram).

Thusfarthisdiscussionof_initialize_and_finalize_hasfailed

toaddressoneimportantpoint:Whyusethisfeaturetoimplementthe

"automatic"callingofconstructorsanddestructorsbecauseitapparently

involvesmoreworkthatsimplycallingtheconstructorsanddestructors

directly?Clearlytheremustbeawaytoautomatetheassignmentofthe

_initialize_and_finalize_stringsorthissectionwouldn'texist.

Thewaytoaccomplishthisisbyusingamacrotodefinetheclasstype.

Sonowit'stimetotakealookatanotherHLAfeaturethatmakesis

possibletoautomatethisactivity:theforwardkeyword.

You'veseenhowtousetheforwardreservedwordtocreateprocedure

prototypes(seethediscussioninthechapteronprocedures),itturnsout

thatyoucandeclareforwardconst,val,type,andvariable

declarationsaswell.Thesyntaxforsuchdeclarationstakesthefollowing

form:

ForwardSymbolName:forward(undefinedID);

Thisdeclarationiscompletelyequivalenttothefollowing:



?undefinedID:text:="ForwardSymbolName";

Especiallynotethatthisexpansiondoesnotactuallydefinethesymbol

ForwardSymbolName.Itjustconvertsthissymboltoastringand

assignsthisstringtothespecifiedtextobject(undefinedIDinthis

example).

Nowyou'reprobablywonderinghowsomethingliketheaboveis

equivalenttoaforwarddeclaration.Thetruthis,itisn't.However,

forwarddeclarationsletyoucreatemacrosthatsimulatetypenamesby

allowingyoutodefertheactualdeclarationofanobject'stypeuntilsome

laterpointinthecode.Considerthefollowingexample:

type

myClass:class

var

i:int32;

procedureCreate;returns("esi");

procedureDestroy;

endclass;



#macro_myClass:varID;

forward(varID);

?_initialize_:=_initialize_+@string:varID+".Create()

?_finalize_:=_finalize_+@string:varID+".Destroy();"

varID:myClass

#endmacro;

Note,andthisisveryimportant,thatasemicolondoesnotfollowthe

"varID:myClass"declarationattheendofthismacro.You'llfindoutwhy

thissemicolonismissinginalittlebit.

Ifyouhavetheclassandmacrodeclarationsaboveinyourprogram,you

cannowdeclarevariablesoftype_myClassthatautomaticallyinvoke

theconstructoranddestructoruponentryandexitoftheroutine

containingthevariabledeclarations.Toseehow,takealookatthe

followingprocedureshell:



procedureHasmyClassObject;

var

mco:_myClass;

beginHasmyClassObject;

<>

endHasmyClassObject;



Since_myClassisamacro,theprocedureaboveexpandstothe

followingtextduringcompilation:

procedureHasmyClassObject;

var

mco://Expansionofthe_myClassmacro

forward(_0103_);//_0103_symbolisanHLA-supplie

//thatexpandsto"mco".

?_initialize_:=_initialize_+"mco"+".Create();";

?_finalize_:=_finalize_+"mco"+".Destroy();";

mco:myClass;

beginHasmyClassObject;



mco.Create();//Expansionofthe_initialize_s

<>



mco.Destroy();//Expansionofthe_finalize_str

endHasmyClassObject;

Youmightnoticethatasemicolonappearsafter"mco:myClass"

declarationintheexampleabove.Thissemicolonisnotactuallyapartof

themacro;insteaditisthesemicolonthatfollowsthe"mco:_myClass;"

declarationintheoriginalcode.

Ifyouwanttocreateanarrayofobjects,youcouldlegallydeclarethat



arrayasfollows:

var

mcoArray:_myClass[10];

Becausethelaststatementinthe_myClassmacrodoesn'tendwitha

semicolon,thedeclarationabovewillexpandtosomethinglikethe

following(almostcorrect)code:



mcoArray://Expansionofthe_myClassmacro

forward(_0103_);//_0103_symbolisanHLA-supplie

//thatexpandsto"mcoArray".



?_initialize_:=_initialize_+"mcoArray"+".Create

?_finalize_:=_finalize_+"mcoArray"+".Destroy();

mcoArray:myClass[10];

Theonlyproblemwiththisexpansionisthatitonlycallstheconstructor

forthefirstobjectofthearray.Thereareseveralwaystosolvethis

problem;oneistoappendamacronametotheendof_initialize_

and_finalize_ratherthantheconstructorname.Thatmacrowould

checktheobject'sname(mcoArrayinthisexample)todetermineifitis

anarray.Ifso,thatmacrocouldexpandtoaloopthatcallsthe

constructorforeachelementofthearray.

Anothersolutiontothisproblemistouseamacroparametertospecify

thedimensionsforarraysofmyClass.Thisschemeiseasierto

implementthantheoneabove,butitdoeshavethedrawbackof

requiringadifferentsyntaxfordeclaringobjectarrays(youhavetouse

parenthesesaroundthearraydimensionratherthansquarebrackets).

Theforwarddirectiveisquitepowerfulandletsyouachieveallkindsof

tricks.However,thereareafewproblemsofwhichyoushouldbeaware.

First,becauseHLAemitsthe_initialize_and_finalize_code

transparently,youcanbeeasilyconfusedifthereareanyerrorsinthe

codeappearingwithinthesestrings.Ifyoustartgettingerrormessages

associatedwiththebeginorendstatementsinaroutine,youmight

wanttotakealookatthe_initialize_and_finalize_strings

withinthatroutine.Thebestdefensehereistoalwaysappendvery



simplestatementstothesestringssothatyoureducethelikelihoodofan

error.

Fundamentally,HLAdoesn'tsupportautomaticconstructoranddestructor

calls.Thissectionhaspresentedseveraltrickstoattempttoautomate

thecallstotheseroutines.However,theautomationisn'tperfectand,

indeed,theaforementionedproblemswiththe_finalize_stringslimit

theapplicabilityofthisapproach.Themechanismthissectionpresentsis

probablyfineforsimpleclassesandsimpleprograms.Onepieceof

adviceisprobablyworthfollowing:Ifyourcodeiscomplexorcorrectness

iscritical,it'sprobablyagoodideatoexplicitlycalltheconstructorsand

destructorsmanually.

[9]Iftheroutineautomaticallyemitscodetoconstructtheactivation

record,HLAemits_initialize_'stextafterthecodethatbuildsthe

activationrecord.

[10]Notethatyoucanmanuallyemitthe_finalize_codeusingthe

statement"@text(_finalize_);".



14.13AbstractMethods

Anabstractbaseclassisonethatexistssolelytosupplyasetof

commonfieldstoitsderivedclasses.Youneverdeclarevariableswhose

typeisanabstractbaseclass;youalwaysuseoneofthederived

classes.Thepurposeofanabstractbaseclassistoprovideatemplate

forcreatingotherclasses,nothingmore.Asitturnsout,theonly

differenceinsyntaxbetweenastandardbaseclassandanabstractbase

classisthepresenceofatleastoneabstractmethoddeclaration.An

abstractmethodisaspecialmethodthatdoesnothaveanactual

implementationintheabstractbaseclass.Anyattempttocallthat

methodwillraiseanexception.Ifyou'rewonderingwhatpossiblegood

anabstractmethodcouldbe,well,keeponreading….

Supposeyouwanttocreateasetofclassestoholdnumericvalues.One

classcouldrepresentunsignedintegers,anotherclasscouldrepresent

signedintegers,athirdcouldimplementBCDvalues,andafourthcould

supportreal64values.Whileyoucouldcreatefourseparateclasses

thatfunctionindependentlyofoneanother,doingsopassesupan

opportunitytomakethissetofclassesmoreconvenienttouse.To

understandwhy,considerthefollowingpossibleclassdeclarations:

type

uint:class

var

TheValue:dword;

methodput;

<>

endclass;

sint:class

var

TheValue:dword;

methodput;

<>

endclass;



r64:class

var

TheValue:real64;

methodput;

<>

endclass;

Theimplementationoftheseclassesisnotunreasonable.Theyhave

fieldsforthedataandtheyhaveaputmethod(which,presumably,

writesthedatatothestandardoutputdevice),Presumablytheyhave

othermethodsandproceduresinimplementvariousoperationsonthe

data.Thereare,however,twoproblemswiththeseclasses,oneminor

andonemajor,bothoccurringbecausetheseclassesdonotinheritany

fieldsfromacommonbaseclass.

Thefirstproblem,whichisrelativelyminor,isthatyouhavetorepeatthe

declarationofseveralcommonfieldsintheseclasses.Forexample,the

putmethoddeclarationappearsineachoftheseclasses.[11]This

duplicationofeffortinvolvesresultsinaharder-to-maintainprogram

becauseitdoesn'tencourageyoutouseacommonnameforacommon

functionbecauseit'seasytouseadifferentnameineachoftheclasses.

Abiggerproblemwiththisapproachisthatitisnotgeneric.Thatis,you

can'tcreateagenericpointertoa"numeric"objectandperform

operationslikeaddition,subtraction,andoutputonthatvalue(regardless

oftheunderlyingnumericrepresentation).

Wecaneasilysolvethesetwoproblemsbyturningthepreviousclass

declarationsintoasetofderivedclasses.Thefollowingcode

demonstratesaneasywaytodothis:

type

numeric:class

procedureput;

<>

endclass;



uint:classinherits(numeric)

var

TheValue:dword;

overridemethodput;

<>

endclass;

sint:classinherits(numeric)

var

TheValue:dword;

overridemethodput;

<>

endclass;

r64:classinherits(numeric)

var

TheValue:real64;

overridemethodput;

<>

endclass;

Thisschemesolvesboththeproblems.First,byinheritingtheput

methodfromnumeric,thiscodeencouragesthederivedclassesto

alwaysusethenameput,therebymakingtheprogrameasierto

maintain.Second,becausethisexampleusesderivedclasses,it's

possibletocreateapointertothenumerictypeandloadthispointer

withtheaddressofauint,sint,orr64object.Thatpointercan

invokethemethodsfoundinthenumericclasstodofunctionslike

addition,subtraction,ornumericoutput.Therefore,theapplicationthat

usesthispointerdoesn'tneedtoknowtheexactdatatype,itonlydeals

withnumericvaluesinagenericfashion.

Oneproblemwiththisschemeisthatit'spossibletodeclareanduse



Tài liệu bạn tìm kiếm đã sẵn sàng tải về

12 HLA's " _initialize_ " and " _finalize_ " Strings

Tải bản đầy đủ ngay(0 tr)

×