concurrent attribute evaluation

7
Pergamon Computing Svsterns in Engineering, Vol. 6, Nos 4:5, pp. 451 457, 1995 Copyright f 1995 ElsevierScienceLtd 0956-0521(95)00028-3 Printed in Great Britain. All rights reserved 0956-0521 ~95 $9.50 + 0.00 CONCURRENT ATTRIBUTE EVALUATION Jo~.o SARAIVAt and PEDRO HENRIQUES~ Departamento de Informfitica, Universidade do Minho, Braga, Portugal Abstract--This text presents an implementation of a concurrent attribute evaluator system. This system was developed with the main objective of allowing the implementation of several strategies of concurrent attribute evaluation and not to build a faster compiler to a specific case. The system is implemented in a tightly-coupled machine. One realistic compiler was built and the first results are discussed. I. INTRODUCTION This text refers to parallel compilers obtained from an attribute grammar (AG) specification. Since compilers are one of the tools programmers use the most, it is obviously relevant to decrease the compilation lime. There are several approaches to speedup compilation time: incremental compilation, separated compilation of program modules and par- allel compilation. The first decreases the compilation time since it compiles only the parts of the source text that have been changed since the last compilation. The second saves time since it compiles only the changed program modules. Parallel compilation saves time since it tries to do at the same time what usually is done in sequence. An obvious strategy, for using parallelism in com- pilation, is to decompose the compiler into its logical phases and allocate a different process (that possibly runs on a different processor) to each of them. The output of one process is the input to the process of the next phase, thus implementing a pipeline. This technique is known as vertical fragmentation. How- ever, this strategy is limited by the fixed and small number of processes used (equal to the number of phases) and by the time taken by the slowest phase. Moreover, it is language independent. Another possible use of parallelism is to have different processes running in parallel in one phase horizontal fragmentation. So, the input of that phase is divided into different (and independent) blocks, each being computed by a different process. There are two approaches that use this kind of parallelism: using syntax-directed translation or using attribute grammars. The implementation of a compiler using the first strategy is possible and was done by Vandervoorde. ~ However, we are interested in study- ing the second approach. Their benefits are specified in the literature. The most important is that an efficient parallel compiler can be automatically pro- + email: jas~a di.uminho.pt. email: prh(a,di.uminho.pt. duced from a specification, relieving the programmer of dealing with parallelism. There are several implementations of this approach.'- ~ We assume that the reader is familiar with the attribute grammar formalism. A more detailed study of the formalism can be found in Refs 5 7. This document is structured as follows: first we describe the conceptual structure of a sequential and a concurrent attribute evaluator. Then we present the system architecture that we have developed to allow parallel attribute evaluation. After that we present several strategies for parallel attribute evaluation that have appeared in the literature. We also describe the strategy implemented in our system. Next we present the attribute evaluator function. At the end we present and analyse the first experimental results obtained in a realistic compiler. Finally, we make some concluding remarks and present what we intend to do in the future. 1.1. Sequential rs paralh'l attribute et:aluation Basically, a compiler is a program that receives another program written in a source language and translates it into a target language, detecting all the errors in the source code. A compiler execution is divided into several stages. ~ At each stage the source program is translated into another representation. Traditionally, a sequential compiler, using attribute grammars, consists of the following stages: scanning, parsing, semantic analysis and intermediate code generation (see Fig. 1). The scanner reads the source text and produces tokens. The parser performs the syntactic analysis and builds a syntactic tree that represents the source text. Then, the attribute evalu- ator function computes all the attribute instances attached to the nodes of the tree. The resulting tree is called a decorated tree. After that any translation operation could be done. The main objective of a concurrent attribute eval- uator is to compute attributes, attached to a syntactic tree, concurrently. So, a concurrent attribute evalua- tor tries to distribute attribute instances, that don't have dependencies between them~ over attribute 451

Upload: joao-saraiva

Post on 15-Jul-2016

212 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Concurrent attribute evaluation

Pergamon Computing Svsterns in Engineering, Vol. 6, Nos 4:5, pp. 451 457, 1995

Copyright f 1995 Elsevier Science Ltd 0956-0521(95)00028-3 Printed in Great Britain. All rights reserved

0956-0521 ~95 $9.50 + 0.00

CONCURRENT ATTRIBUTE EVALUATION

Jo~.o SARAIVAt and PEDRO HENRIQUES~

Departamento de Informfitica, Universidade do Minho, Braga, Portugal

Abstract--This text presents an implementation of a concurrent attribute evaluator system. This system was developed with the main objective of allowing the implementation of several strategies of concurrent attribute evaluation and not to build a faster compiler to a specific case. The system is implemented in a tightly-coupled machine. One realistic compiler was built and the first results are discussed.

I. INTRODUCTION

This text refers to parallel compilers obtained from an attribute grammar (AG) specification.

Since compilers are one of the tools programmers use the most, it is obviously relevant to decrease the compilat ion lime. There are several approaches to speedup compilat ion time: incremental compilation, separated compilation of program modules and par- allel compilation. The first decreases the compilation time since it compiles only the parts of the source text that have been changed since the last compilation. The second saves time since it compiles only the changed program modules. Parallel compilation saves time since it tries to do at the same time what usually is done in sequence.

An obvious strategy, for using parallelism in com- pilation, is to decompose the compiler into its logical phases and allocate a different process (that possibly runs on a different processor) to each of them. The output of one process is the input to the process of the next phase, thus implementing a pipeline. This technique is known as vertical fragmentation. How- ever, this strategy is limited by the fixed and small number of processes used (equal to the number of phases) and by the time taken by the slowest phase. Moreover , it is language independent.

Another possible use of parallelism is to have different processes running in parallel in one phase horizontal fragmentation. So, the input of that phase is divided into different (and independent) blocks, each being computed by a different process. There are two approaches that use this kind of parallelism: using syntax-directed translation or using attribute grammars. The implementation of a compiler using the first strategy is possible and was done by Vandervoorde. ~ However, we are interested in study- ing the second approach. Their benefits are specified in the literature. The most important is that an efficient parallel compiler can be automatically pro-

+ email: jas~a di.uminho.pt. email: prh(a,di.uminho.pt.

duced from a specification, relieving the programmer of dealing with parallelism. There are several implementations of this approach.'- ~ We assume that the reader is familiar with the attribute grammar formalism. A more detailed study of the formalism can be found in Refs 5 7.

This document is structured as follows: first we describe the conceptual structure of a sequential and a concurrent attribute evaluator. Then we present the system architecture that we have developed to allow parallel attribute evaluation. After that we present several strategies for parallel attribute evaluation that have appeared in the literature. We also describe the strategy implemented in our system. Next we present the attribute evaluator function. At the end we present and analyse the first experimental results obtained in a realistic compiler. Finally, we make some concluding remarks and present what we intend to do in the future.

1.1. Sequential rs paralh'l attribute et:aluation

Basically, a compiler is a program that receives another program written in a source language and translates it into a target language, detecting all the errors in the source code. A compiler execution is divided into several stages. ~ At each stage the source program is translated into another representation.

Traditionally, a sequential compiler, using attribute grammars, consists of the following stages: scanning, parsing, semantic analysis and intermediate code generation (see Fig. 1). The scanner reads the source text and produces tokens. The parser performs the syntactic analysis and builds a syntactic tree that represents the source text. Then, the attribute evalu- ator function computes all the attribute instances attached to the nodes of the tree. The resulting tree is called a decorated tree. After that any translation operation could be done.

The main objective of a concurrent attribute eval- uator is to compute attributes, attached to a syntactic tree, concurrently. So, a concurrent attribute evalua- tor tries to distribute attribute instances, that don' t have dependencies between them~ over attribute

451

Page 2: Concurrent attribute evaluation

452 Jofio Saraiva and Pedro Henriques

SyntacticTree Decorated Tree

Fig. 1. The conceptual structure of a sequential compiler.

evaluator processes. Those attributes will be evaluated concurrently.

It is the existence of this mechanism of distribution and the attribute evaluator processes that makes the main difference between the concurrent and the sequential compiler (see Fig. 2). The mechanism of distribution is responsible for the obtained degree of concurrency. This mechanism has the compromise of increasing the concurrency and decreasing the communication overhead.

Another possibility for increasing the potential parallelism of compilers is to perform the attribute evaluation during the parsing. 3"9 This approach could be achieved as follows: when a part of the tree is built one evaluator process is allocated to it. So, the attribute evaluation is started as soon as possible. With this approach the distributor is part of the parser. This technique could be easily implemented in LAGs. The architecture of the system, presented below, doesn't implement this technique.

In this work we are essentially interested in study- ing the mechanism of distribution--the Splitter--and the concurrent attribute evaluation. That corre- sponds to the rectangular area of Fig. 2.

2. LANGUAGE PROCESSOR IMPLEMENTATION: SYSTEM ARCHITECTURE

The concurrent compiler is based on three different kinds of processes: the main process--Main--, the event handler--EventHandler--and the process that provides the attribute evaluator--ServEval. These processes and the communication between them are shown in Fig. 3.

In this approach, data must be shared by different processes. Once the Main process builds a syntactic tree and the attribute evaluator processes decorate that same tree, they have to share it. Also, if there are any direct dependencies between attribute instances, allocated to different processes, these processes must share those instances. In this implementation, the shared memory mechanism was used to exchange information between processes. So, the syntactic tree is stored in the shared memory, as well as all the attribute instances, since those values are attached to the nodes of that syntactic tree. We chose that mechanism because it was available in the hardware where the system was implemented. We could choose other strategies for passing data between processes. Instead of using shared memory, we could implement

Text

SyntacticTree Attribute Decorated Tree Evahat0r Processes:

Fig. 2. The conceptual structure of a concurrent compiler

Page 3: Concurrent attribute evaluation

Concurrent attribute evaluation 453

Shared Memor

Event Handler

Fig. 3. Concurrent compiler architecture.

a p rocess - - se rver - - tha t would handle the syntactic tree and the attribute instances. Thus, the syntactic tree and the attribute instances would be available to all the processes through that server. The implemen- tation of this strategy is not difficult, but we think it is not relevant to the work we are doing. However, this strategy must be implemented if we don ' t have the shared memory mechanism.

A semaphore was implemented to assure the mutual exclusion in the access, of the different processes, to the shared memory.

The communicat ion between two kinds of process is based on the event concept. These events may be implemented using any communicat ion mechanism. The event specifies the task and the attribute over which it will be executed. All the events the system handles will be specified later. In order to establish a correct synchronization between all the processes and a scheduler for the attribute evaluator processes, an event handler was implemented.

In the rest of this section the processes on which the system architecture is based will be briefly described.

The Main process parses the source text and builds its syntactic tree in the shared memory. Then, the splitter walks through the syntactic tree and divides it into subtrees, according to a predefined strategy (which will be discussed in detail in Sec. 3.2). These subtrees are sent to the event handler, by the even t - -

ClientReqnest, and later, to an attribute evaluator process. This event specifies the subtree and the attribute, or attributes, that will be evaluated in that subtree. This allows attributes in the same subtree to be evaluated by different instances of the same attribute evaluator process. When the function splitter has worked through the whole tree, it sends an event - -Cl ientEndOfReques t - - to the event handler saying that no other subtree will be sent. The Main process waits for an event--ClientWaitService- Comp~from the event handler stating that all the subtrees have been evaluated. Any translation operation necessary to complete the compiler 's task (code generation, optimization, etc.) will be per- formed by the Main process after the receipt of this event. Before finishing, the main process must inform the event handler through the event ClientFinished. At the beginning, this process creates the event handler process, passing to it the number of attribute evaluator processes and their name.

The event handler is the process that distributes the requests sent by the splitter to the attribute evaluator processes servers. Thus, this process has to provide a scheduler for those servers, sending them requests if they are free and marking them as busy, when they are processing a subtree. The event handler is also responsible for the management of those servers waiting for an attribute instance, so that they can

Page 4: Concurrent attribute evaluation

454 Jo~o Saraiva and Pedro Henriques

proceed when that attribute instance is computed. This process still has a queue to save requests, sent by the Main process, which cannot be satisfied due to the fact that all the servers are busy. In this case the request is saved in the queue and it is processed later, as soon as one of the servers is free. This queue is a FIFO, so the first request received is the first to be processed (there are no priorities). It is the event handler that creates the specified number of instances of the attribute evaluator process. This process also performs the initial synchronization of all the pro- cesses, through the events--ClientSynchronization-- and--ServerSynchronization.

The last kind of process, in which the concurrent compiler is based, is the attribute evaluator-- ServEval. This process will have several instances, to which will be sent subtrees to be processed (deco- rated) concurrently. The number of instances of this process, required by the user, is specified when the compiler is called. This process waits for requests to process subtrees, which are made by the event handler through an event--ServerRequest. Thus, every time the attribute evaluator process receives this event, it calls the function that performs the attribute evaluation--function Eval 0 (this function is described in Sec. 4). When this function evaluates an attribute instance, on which another attribute instance (allocated to a different evaluator process) depends, it sends an event--ServerEvaluatedAttrib-- saying that the attribute instance was evaluated and then proceeds with the subtree decoration. The Event Handler receives that event and checks if any attribute evaluator is dormant waiting for that attribute instance. In that case, the process is woken up through the event--ServerWakeUp. After pro- cessing the subtree, the attribute evaluator must tell the event handler it is ready to receive another subtree--ServerFinished.

All the attribute instances have a tag--AtribCalc-- that indicates whether the attribute has been calcu- lated or not. So, if the evaluator needs an attribute instance which has not yet been calculated, it sends an event--ServerWait~to the event handler and becomes dormant waiting for that instance. This event specifies the attribute instance that the calcula- tor needs in order to go on. On the other hand, the event handler advises this process to continue the evaluation, as soon as the attribute instance is evaluated. This is done through the event Server- WakeUp, as described above.

The compiler is called by the following command line:

Main[-c(Number of Servers)]

This command specifies the main process and (optionally) the number of instances of the attribute evaluator process. If this number of instances is not specified the compiler runs sequencially, without any overhead due to the parallelism.

This architecture was implemented in a com- puter--Solbourne Computer-Series 700--with four processors (Sparc) with shared memory. The system runs under the Unix operating system. So, the events are implemented using the messages mechanism of that operating system. The semaphore and the shared memory were also implemented using the system calls of the Unix operating system.

3. SPLITTER STRATEGY

3.1. Introduction and related work

The main objectives of a splitter strategy are:

• to permit independent attribute instances to be evaluated concurrently

• to minimize the communication between evalua- tor processes.

The greatest grain of parallelism is obtained using one process for each tree node, increasing the inter- process communication. The lowest communication overhead is obtained using the same process to compute all the tree. So, a compromise solution must be found.

There are several strategies for distributing attribute instances over the evaluator processes, t°

Kuiper '1 proposes three (static) methods for the distribution:

• tree based distributors • attribute based distributors • combined distributors.

The first method splits the tree into connected parts, called regions, and uses the same process to evaluate all attribute instances attached to a region. One region is defined by the common ancestor of all the nodes in that region. To define a region it suffices to specify which node is the common ancestor of all the nodes in that region. There are two different ways of selecting the common ancestor: using the production applied to a node--production based distributor--or using the nonterminal labeling a node--nonterminal based distributor. In an attribute based distributor all the attribute instances or all instances of an attribute occurrence are evaluated by the same process. The last method is the combination of the first two.

Kuiper also proposes an optimized version of a parallelism detector for attribute grammars. '2 He presents an algorithm for statically detecting independent attribute instances. This algorithm computes all possible dependencies among attribute instances, in order to know which attribute instances are independent. The results obtained applying the algorithm can be the basis for building the distributor function.

Klein 4 proposes an approach based on the segment concept. For each production the attributes are (stati- cally) divided into disjoint sets~egments--wi th the

Page 5: Concurrent attribute evaluation

Concurrent attribute evaluation 455

condition that, for every instance of a non-terminal (in all productions), each two attributes (of that non-terminal) are always in the same segment or always in different ones. Then, when attributes of different productions overlap at some tree node, their segments are joined. This is done at run time. Each set (segment) obtained is allocated to a distinct evaluator process. In this approach, there must be a total order for all the attribute instances that belong to the same segment (the attribute grammar must be OAG or LAG). However, Klein does not propose any strategy for defining the division of the attributes in segments, according to their dependencies.

Another possible way to perform the parallel attribute evaluation is to modify the evaluator based on visit-sequencies to provide parallel execution. The basic idea of this approach is to maintain the evalu- ation order of the attribute instances of a node, but to evaluate and visit those nodes in parallel. This approach was first presented by Schel113 and more recently proposed by Zaring ~4 and Jourdan. l° Schell presents several modifications to adapt the well- known attribute evaluator algorithms to produce parallel traversals. Zaring presents several algorithms categorized according to the style of parallelism they exhibit--synehronous or asynchronous--and the kind of visit-sequence instructions they can perform in parallel--Eval, Visit and Leave. Jourdan has implemented this approach with good results and he explains in detail how it can be efficiently obtained.

A different approach is proposed by RepsJ 5 He uses a data parallelism model and defines a new class of attribute grammars--scan-grammars- designed so that attributes can be evaluated in a data parallel fashion. Basically, he computes attributes, whose dependencies form a long chain (like the symbol table attribute)+ as partial sums (by a given associative operator) in a tree traversal, called scan-attribution. Using data-parallelism, a scan-attribution can be per- formed in a list of length k in 2*[log k] + 1 steps, by representing the list in a balanced binary tree of depth log k. Since this is a recent approach, it deserves a deeper study.

3.2. The strategy implemented

The system, described in the previous section, was developed to make possible an easy implementation of several distribution strategies. So, all the Kuiper methods could be implemented in this system.

At present, the distribution of the attribute instances over the evaluator processes is not auto- matically decided. However, the system was built to provide an easy way to implement semi-automatically (see Sec. 4) a parallel evaluator for a given AG.

For performing the distribution we have implemented one func t ion- -Spl i t t e~ tha t walks through the syntactic tree and divides it into parts. This function must be compatible with the evaluation order determined for the attribute instances. A tree part corresponds to a subtree and a set of its

attributes (not necessarily all). The tree division is made according to the nodes that we specify as split nodes. A split node is the common ancestor of all the nodes of one part of the tree (like the select nodes of Kuiper). The split nodes are specified in the Splitter function as follows: associated with each split node type is an event--CiientRequest--that allocates one evaluator process to the part defined by that node. So, when the Splitter visits nodes of that type is passes each part to one evaluator process, stating the attribute or attributes that will be evaluated. The specification of the attributes, that will be computed in a subtree, allows the concurrent evaluation of independent attributes in that subtree. Thus, to decorate a subtree it will be necessary to evaluate all the parts specified in that subtree.

Since, each part of the tree is evaluated by a different process, the evaluator function must com- pute the values of all the attribute instances attached to that part. So, there must be a visit order for each attribute set of each part of the tree.

As the splitting strategy is specified in a function, it is possible to have different grains of parallelism just by modifying that function.

The specification of the attributes that will be evaluated in each part permits the implementation of the combined distributor method, since we define a part of the tree and the attributes that will be evaluated in that part. For implementing the attribute based distributor, the split nodes set will be singular (with the tree root node as its unique element) and we will allocate an evaluator process to compute each attribute in the whole tree. Specifying that the evaluator process computes all the attributes in a part, we implement the tree based distributor.

4. ATTRIBUTE EVALUATOR: FUNCTION "EVAL"

In order to compute the attribute instances in a syntactic tree, an attribute evaluator must be built. We obtain this evaluator using the Ag, '7 which is a (sequential) attribute evaluator generator. It pro- cesses ordered attribute grammars (OAGs ) and gener- ates a treewalker evaluator (function Eval) which is based on t:isit-sequenees to the nodes of the abstract syntax tree. The AG describes the structure of all possible trees, the attributes and the attribute computations.

Once the Ag generates a sequential evaluator function, this function must be modified to permit parallel evaluation.

The parallel evaluator function has the following parameters: a pointer to the subtree root that will be processed and the set of attributes that will be evaluated. So, for each attribute this function must compute all its instances (in that subtree). Once Ag allows modular AG specifications, we could use this to specify each tree part is a module and obtain the corresponding evaluator function. However+ if one tree part contains another, we must be careful to

Page 6: Concurrent attribute evaluation

456 Joio Saraiva and Pedro Henriques

Table 1. Sequencial and concurrent execution time (in seconds)

Strategy I Strategy 2

2000 1000 2000 Lines time time time

Sequential: AEt time 1.743 0.878 1.754

With one processor: AE time 1.785 0.888 1.849 Global 1.095 1.006 1.981

With 2 processors: AE 1.788 0.467 0.964 Global 1.938 0.614 1.117

With 3 processors: AE 1.803 0.354 0.713 Global 1.993 0.545 0.909

With 4 processors: AE 1.810 0.269 0.548 Global 2.050 0.499 0.783

tAttribute Evaluation.

specify the A G for the second one only once. The parallel attribute evaluator function is the union of all these (sequential) evaluator functions.

When visiting one split node, the parallel evaluator must execute the following steps: verify if the needed attribute instances are computed. If not, it must tell that to the event handler and become dormant. If the attribute instances are computed, it continues with the usual visit-sequences. At the end it tells the event handler which attribute instances were evaluated.

If one subtree, that is being decorated by one evaluator process, has children marked as split nodes, the usual visit-sequences must be modified in order to avoid visiting (and computing) those nodes. This is due to those nodes being roots of other subtrees which will be evaluated by other processes. In that case it is only necessary to notify, as soon as possible, the event handler which attribute instances were evaluated once there are other processes waiting for those instances.

The modifications made in this function and the splitter are shown in an example in the Appendix.

5. RESULTS

This compiler was run with two different source texts (with 1000 and 2000 lines, respectively) and two different splitter strategies. The first results obtained are shown in the tables below. These results represent the time (in Table 1) and the speedupt (in Table 2) of pure attribute evaluation and total execution of the compiler. Table 1 includes the time (in seconds) of the compiler sequential execution and of the execution on one thought to four processors. Table 2 shows the speedup obtained with two, three and four processors.

These two splitter strategies were obtained by just modifying the splitter function, i.e. by changing the split nodes.

In both strategies the compiler running with one processor is only 13% slower than the sequential evaluator. This means that the communicat ion overhead, due to the parallelism is small.

The first splitter strategy is a bad one. It splits the syntactic tree into parts, each part, evaluated concurrently, is a subtree rooted on a context node. Since the symbol table inherited by a context depends on that of the previous context, the attribute evaluation is performed in a sequential manner. As we can see in the table above, the compilation time increases with the number of processors due to the communicat ion and processes creation over- head. Thus, we don ' t have any gain with the parallelism.

The second strategy splits the syntactic tree to perform the attribute evaluation of the context body in parallel. Once the attribute instances of two differ- ent context bodies are independent they can really be computed in parallel. The speedup increases with the number of processors. The speedup obtained in pure attribute evaluation is greater than the global speedup. This is due to the process creation overhead. We think that this overhead is so significant because the semantic analysis of the (_9 language is quite simple.

These two strategies have opposite results. In the first one compilation time is increased, while in the second one it is drastically decreased. So, it is obvious that a good splitter strategy is essential to obtain positive results.

The strategy described above was implemented in a realistic parallel compiler. The compiler translates the (9 language into Lisp. The C language is an object oriented language developed in this department. ~8'19 Its main concept is the context. One context describes several objects, the relations among them and their behaviour. Since this is a recent language, we are still not quite familiar with the typical texts written in this source language. So the source texts used in the experiments could not represent a typical C text.

t The speedup is the ratio of sequential to parallel evalu- ation time.

Table 2. Speedup for strategy 2

Speedup for strategy 2

Lines 1000 2000

With 2 processors: AE 1.88 1.82 Global 1.43 1.57

With 3 processors: AE 2.48 2.46 Global 1.61 1.93

With 4 processors: AE 3.27 3.20 Global 1.76 2.24

Page 7: Concurrent attribute evaluation

Concurrent attribute evaluation 457

The results o f the first expe r imen t s are e n c o u r a g i n g and p rove that paral lel a t t r ibu te eva lua t ion is poss - ible. Better results could be ob t a ined if the semant i c analys is o f the source l anguage requires m o r e c o m p u t a t i o n .

6. CONCLUSION

We have p resen ted a sys tem arch i tec ture that a l lows the paral lel a t t r ibu te eva lua t ion . This archi tec- ture was i m p l e m e n t e d in a real compi l e r and the first ob t a ine d results are p romis ing . So, it seems thai parallel a t t r ibu te eva lua t ion is one efficient way to spe e dup compi la t ion .

As fu ture work we in tend to imp lemen t m o r e A G s in ou r sys tem to conf i rm the first results. We also aim at m a k i n g it poss ib le t o p a r a m e t e r i z e the sys tem with the set o f split nodes.

I6. J. Grosch. Ag- -an attribute evaluator generator. Research Report 16, Gesellschaft fur Mathematik und Datenverarbeitung an der Universitaet Karlsruhe, March 1991.

17. J. M. Valem;a. Proeessos, Objeoto3' e (-omunica~.ao (Opgdo I-MCC). Departamento de Informfitica. Universidade do Minho, Outubro 1990.

18. J. Saraiva. Um Compilador para a Linguagem O. Departamento de Informfitica, Universidade do Minho, Setembro 1991.

STRATEGY IMPLEMENTED: AN EXAMPLE

In this appendix we will present an example that shows the necessary changes in the treewalker evaluator to allow parallel evaluation. The splitter function is also presented.

A possible visit-sequence associated to the non-terminal X is shown below. The non-terminal has two children Y and Z, according to the production:

X--~ YZ

REFERENCES

I. M. T. Vandevoorde. Parallel compilation on a tightly coupled multiprocessor. Research report, DIGITAL Systems Research Center, March 1988.

2. H.-J. Boehm and W. Zwaenepoel. "Parallel attribute grammar evaluation," Proceedings 7th International Conference on Distributed Computing Systems, 1987 pp. 347 354.

3. M. F. Kuiper and A. Dijkstra. "Attribute evaluation on a network of transputers,'" in Developing Transputer Applications, Proceedings of the l lth Occam User Group Technical Meeting, 1989 pp. 142 149.

4. E. Klein. Parallel ordered attribute grammars. Research report, Gesellschaft fur Mathematik und Datenverar- beitung an der Universitaet Karlsruhe, June 1992.

5. P. Deransart and M. Jourdan (eds). Attribute Grammars and their Applications. Lecture Notes in Computer Science, Springer-Verlag, September 1990.

6. H. Alblas and B. Melichar (eds). Attribute Grammars, .4pplications and Systems. Lecture Notes in Computer Science 545, Springer-Verlag, June 1991.

7. P, R. Henriques, Gramatieas de Atributos. Departa- menlo de lnformfitica, Universidade do Minho, Janeiro 19q2.

8. A. V. Aho, R. Sethi, and J. D. Ullman. Compilers Principh,.s, Techniques and Tools. Addison-Wesley, 1986.

9. E. Klein and K. Koskimies, "'Parallel one-pass compi- lation.'" in WAGA-90, LNCS 461, Springer-Verlag, 1990 pp. 76 90.

I1). M. Jourdan. "A survey of parallel attribute evaluation methods," in h~ternational Summer School on Attribute Grammars, Applications and Systems, LNCS 545, Springer-Verlag, 1991 pp. 234 255.

11. M. F. Kuiper. Paralh, l attribute etaluation. PhD thesis, Utrech University. November 1989.

12. M F. Kuiper. Speeding up Parallelism Detection for Attribute Grammars. Research Report RUU-CS-92-18, Dcp. of Computer Science/Utrecht Univ., April 1992.

lY R. M. Sche[1. Methodslbreonstructionparalh, lcompilers /or use in a muhiprocessor environment. PhD thesis, University of Illinois, 1979.

14. A. K. Zaring. ParalM evaluation in attribute grammar- bayed .U'stems. PhD thesis, Cornell University, August 1990.

15. T. Reps. Scan grammars: Parallel attribute evaluation via data-parallelism. Research report, University of Wisconsin Madison, November 1992.

X: Y: child I .atin~--X.atin Y.atout~--fl (Y .atin ) Visit child I Leave child2.atin~---X.atin Visit child2 Z: X.at out*--child.ato ut + Z.atout~-f2(Zatin)

child2.atout Leave Leave

Next, we show the treewalker, modified to pcrmil the decoration of the parent - -X and its children Yand Z , by difl'erent evaluator processes. In the modified treewalker evaluator the visit to the children is not performed, since they will be evaluated by other processes (see the splitter function). The attribute X.atout depends on attribute m- stances of the children. Then it can only be evaluated when those instances have already been evaluated. The treewalker waits for that, through the function getAttribute().

The processes responsible for decorating the children nodes must wait l\)r the parent's attribute instances they need. This is done through the function getAttribute().

X: child I .atin,~--X.atin child2.atin~X.atin getAttribute (child I.atout,child2.atout) X.atout,--child l.atout + child2.atout) putAttribute (X.atout) Leave

Y: Z: getAttribute(atin) getAttribute(atin) Y.atout+--fl [Y.atin) Z.atout~f2[Z.atin) putAttribute(atout) putAttribute(atout) Leave Leave

The splitter function is presented next. When visiting the node associated with the non-terminal X the splitter func- tion activates two attribute evaluator processes and sends them the two nodes. Then they will be evaluated concur- rently since (in this example) there arc ilo dependencies between their attribute instances.

Splitter (treeptr) [case X: ClientRequest (treeptr.childl,at)

ClientRequest (treeptr.child2,at)