Cooper_Engineering_a_Compiler(Second Edition) (Rice), страница 73

Rice 1869

Описание файла

Файл "Cooper_Engineering_a_Compiler(Second Edition)" внутри архива находится в следующих папках: Rice, Купер и Торчсон - перевод. PDF-файл из архива "Rice", который расположен в категории "разное". Всё это находится в предмете "конструирование компиляторов" из седьмого семестра, которые можно найти в файловом архиве МГУ им. Ломоносова. Не смотря на прямую связь этого архива с МГУ им. Ломоносова, его также можно найти и в других разделах. .

Просмотр PDF-файла онлайн

Текст 73 страницы из PDF

};public void move() { ... };}class ColorPoint extends Point {// inherits x, y, & move()Color c;// local field of ColorPointpublic void draw() { ... };// hide Point’s draw()public void test() { ...; draw(); };// local method}class C {int x, y;public void m() {// local fields// local methodint y;// local variable of mPoint p = new ColorPoint();// uses ColorPoint and, byy = p.x// inheritance, Pointp.draw()}}n FIGURE 6.6 Definitions for Point and ColorPoint.288 CHAPTER 6 The Procedure AbstractionTo translate this example, the compiler must track the hierarchy of namesand scopes established both by the scope rules inside methods and classesand by the hierarchy of classes and superclasses established by extends.Name resolution in this environment depends on both the details of the codedefinitions and the class structure of the data definitions. To translate an ool,the compiler needs to model both the name space of the code and the namespaces associated with the class hierarchy.

The complexity of that modeldepends on details of the specific ool.In Java, public makes a name visibleeverywhere while private makes the namevisible only within its own class.To add a final complication, some ools provide attributes for individualnames that change their visibility. For example, a Java name can have theattributes public or private.

Similarly, some ools provide a mechanism toreference names obscured by nesting. In c++, the :: operator allows the codeto name a scope while in Java the programmer can use a fully qualified name.Naming in the Class HierarchyThe class hierarchy defines a set of nested name scopes, just as a set of nestedprocedures and blocks does in an all. In an all, lexical position defines therelationship between those name scopes—if procedure d is declared insideprocedure c, then d’s name space is nested inside c’s name space.

In an ool,the class declarations can be lexically disjoint and the subclass relation isspecified by explicit declarations.Direct superclassIf class α extends β, then β is α’s directsuperclass. If β has a superclass γ , then γ is, bytransitivity, a superclass of α, but it is not α’sdirect superclass.To find the declaration of a name, the compiler must search the lexical hierarchy, the class hierarchy, and the global name space.

For a name x in amethod m, the compiler first searches the lexical scopes that surround thereference in m. If that lookup fails, it searches the class hierarchy for theclass that contains m. Conceptually, it searches m’s declared class, then m’sdirect superclass, then that class’ direct superclass, and so on until it findsthe name or exhausts the class hierarchy. If the name is not found in eitherthe lexical hierarchy or the class hierarchy, the compiler searches the globalname space.To support the more complex naming environment of an ool, the compilerwriter uses the same basic tools used with an all: a linked set of symboltables (see Section 5.5.3).

In an ool, the compiler simply has more tablesthan in an all and it must use those tables in a way that reflects the namingenvironment. It can link the tables together in the appropriate order, or it cankeep the three kinds of tables separate and search them in the appropriateorder.The major complication that arises with some ools derives not from thepresence of a class hierarchy, but rather from when that hierarchy is defined.If the ool requires that class definitions be present at compile time and that6.3 Name Spaces 289TRANSLATING JAVAThe Java programming language was designed to be portable, to besecure, and to have a compact representation for transmission over networks. These design goals led directly to a two-stage translation schemefor Java that is followed in almost all Java implementations.Java code is first compiled, in the traditional sense, from Java source intoan IR called Java bytecode.

Java bytecode is compact. Java bytecode formsthe instruction set for the Java Virtual Machine (JVM). The JVM has beenimplemented with an interpreter that can be compiled on almost anytarget platform, providing portability. Because Java code executes insidethe JVM, the JVM can control interactions between the Java code and thesystem, limiting the ability of a Java program to gain illicit access to systemresources—a strong security feature.This design implies a specific translation scheme.

Java code is first compiledinto Java bytecode. The bytecode is then interpreted by the JVM. Becauseinterpretation adds runtime overhead, many JVM implementations includea just-in-time compiler that translates heavily used bytecode sequencesinto native code for the underlying hardware. As a result, Java translationis a combination of compilation and interpretation.class definitions not change after compile time, then name resolution insidemethods can be performed at compile time. We say that such a languagehas a closed class structure. On the other hand, if the language allows therunning program to change its class structure, either by importing classes asin Java or by editing classes as in Smalltalk, then the language has an openclass structure.Given a method m, the compiler can map a name that appears in m to eithera declaration in some nested scope of m, or to the class definition that contains m.

If the name is declared in a superclass, the compiler’s ability todetermine which superclass declares the name depends on whether the classstructure is open or closed. With a closed class structure, the compiler hasthe complete class hierarchy, so it can resolve all names back to their declarations and, with appropriate runtime structures to support naming, cangenerate code to access any name. With an open class structure, the compiler may not know the class structure until runtime.

Such languages requireruntime mechanisms to resolve names in the class hierarchy; that requirement, in turn, typically leads to implementations that rely on interpretationor runtime compilation. Similar situations can arise from explicit or implicitconversions in a language with a closed class structure; for example virtualfunctions in c++ may require runtime support.Closed class structureIf the class structure of an application is fixed atcompile time, the OOL has a closed hierarchy.Open class structureIf an application can change its class structure atruntime, it has an open hierarchy.c++ has a closed class structure. Any functions,other than virtual functions, can be resolved atcompile time.

Virtual functions require runtimeresolution.290 CHAPTER 6 The Procedure Abstraction6.3.4 Runtime Structures to Support Object-OrientedLanguagesJust as Algol-like languages need runtime structures to support their lexicalname spaces, so too do object-oriented languages need runtime structures tosupport both their lexical hierarchy and their class hierarchy.

Some of thosestructures are identical to the ones found in an all. For example, the controlinformation for methods, as well as storage for method-local names, is storedin ars. Other structures are designed to address specific problems introducedby the ool. For example, object lifetimes need not match the invocation ofany particular method, so their persistent state cannot be stored in some ar.Thus, each object needs its own object record (or) to hold its state. The orsof classes instantiate the inheritance hierarchy; they play a critical role intranslation and execution.The amount of runtime support that an ool needs depends heavily on features of the ool.

To explain the range of possibilities, we will begin with thestructures that might be generated for the definitions in Figure 6.6, assuming a language with single inheritance and an open class structure. From thatbase case, we will explore the simplifications and optimizations that a closedclass structure allows.Figure 6.7 shows the runtime structures that might result from instantiating three objects using the definitions from Figure 6.6. SimplePointinstantiates Point, while both LeftCorner and RightCorner instantiateColorPoint. Each of object has its own or, as do the classes Point and-classmethodssuperclassclass methods••••- draw-classmethodssuperclassclass methodsColorPoint movetest••••- drawmovePoint•class•methodsx 1022y 14- drawmove•class•methodsx 84y 364SimplePoint- drawc blueLeftCornern FIGURE 6.7 Runtime Structures for the ColorPoint Example.movetest?-?classmethodssuperclassclass methods••••class•class•methodsx 278y 16- drawc redRightCornermovetest6.3 Name Spaces 291ColorPoint.

For completeness, the diagram shows an or for class class.Depending on the language, an implementation may avoid representingsome of these fields, method vectors, and pointers.The or for a simple object, such as LeftCorner, contains a pointer to theclass that defined LeftCorner, a pointer to the method vector for that class,and space for its fields, x, y, and c, Notice that the inherited fields in aColorPoint and in its method vector have the same offset that they wouldin the base class Point. The or for ColorPoint literally extends the orfor Point. The resulting consistency allows a superclass method such asPoint.move to operate correctly on a subclass object, such as LeftCorner.The or for a class contains a pointer to its class, class, a pointer to themethod vector for class, and its local fields which include superclassand class methods. In the figure, all method vectors are drawn as completemethod vectors—that is, they include all of the methods for the class, bothlocal and inherited.

The superclass field records the inheritance hierarchy,which may be necessary in an open class structure. The class methods fieldpoints to the method vector used members of the class.To avoid a confusing tangle of lines in the figure, we have simplified themethod vectors in several ways. The drawing shows separate method vectorsrather than pointers to a shared copy of the class methods vectors. The copiesare drawn in gray. Class class has null pointers for both its methods andits class methods fields.

In a real implementation, these would likely havesome methods, which would, in turn, cause non-null pointers in the methodsfield of both Point and ColorPoint.Method InvocationHow does the compiler generate code to invoke a method such as draw?Methods are always invoked relative to an object, say RightCorner, asreceiver. For the invocation to be legal, RightCorner must be visible atthe point of the call, so the compiler can discover how to find RightCornerwith a symbol-table lookup. The compiler first looks in the method’s lexicalhierarchy, then in the class hierarchy, and, finally, in the global scope. Thatlookup provides enough information to let the compiler emit code to obtaina pointer to RightCorner’s or.Once the compiler has emitted code to obtain the or pointer, it locates themethod vector pointer at offset 4 in the or pointer.

Свежие статьи
Популярно сейчас