0% found this document useful (0 votes)
848 views9 pages

Attribute Grammars - PPL

Attribute grammars extend context-free grammars by associating additional attributes with grammar symbols. Attributes represent properties like types and values, allowing attribute grammars to describe both the syntax and static semantics of programming languages. Semantic functions compute attribute values while predicates check rules. Examples show how attributes enforce type checking and name consistency.

Uploaded by

alukapellyvijaya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
848 views9 pages

Attribute Grammars - PPL

Attribute grammars extend context-free grammars by associating additional attributes with grammar symbols. Attributes represent properties like types and values, allowing attribute grammars to describe both the syntax and static semantics of programming languages. Semantic functions compute attribute values while predicates check rules. Examples show how attributes enforce type checking and name consistency.

Uploaded by

alukapellyvijaya
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 9

Attribute Grammars

Context-Free Grammar (CFG):

 This is a grammar used to describe the syntax of programming languages.


 It consists of a set of production rules that define how valid sentences (or programs) can be
formed from the language's symbols.

Attribute Grammar (AG):

 An attribute grammar extends the capabilities of a context-free grammar.


 It allows us to associate additional information, called attributes, with the symbols of the
grammar.
 These attributes can represent properties like types, values, or any other information relevant
to the language being described.
 While a context-free grammar primarily deals with the structure of a language, an attribute
grammar helps describe additional properties or behaviors of the language. For example, in a
programming language, we use attribute grammar to specify type compatibility rules, which
aren't easily captured by context-free grammar alone.

Static Semantics

 BNF is a notation used to describe the syntax of programming languages. However, certain
characteristics, like type compatibility rules, are challenging to express solely with BNF.
For instance, in Java, stating that a floating-point value cannot be assigned to an integer type
variable isn't straightforward with BNF without adding complexity.
 If all typing rules of a language were to be specified in BNF, the resulting grammar would
become overly large and complex. This is problematic because the size of the grammar
directly affects the efficiency of the syntax analyzer used during compilation.
 Certain language rules, such as the requirement that variables must be declared before they are
referenced, cannot be expressed using BNF. This limitation is due to the nature of BNF,
which is designed to describe the syntax rather than the static semantics of a language.
 These issues showcase the types of language rules known as static semantics rules.
 The static semantics of a language is only indirectly related to the meaning of programs
during execution; rather, it has to do with the legal forms of programs (syntax rather
than semantics).

 Many static semantic rules revolve around type constraints, specifying how types can interact
within the language and ensuring type safety.
 Due to the limitations of BNF in describing static semantics, more powerful mechanisms like
attribute grammars have been developed. Attribute grammars, introduced by Donald Knuth in
1968, are a formalism that extends context-free grammars to describe both syntax and static
semantics of programming languages.
 Attribute grammars provide a structured way to define attributes associated with
language constructs and specify rules for computing these attributes. They allow for the
formal description and verification of static semantic rules, enabling the checking of
correctness during compilation.

Basic Concepts

 Attribute grammars are context-free grammars to which have been added attributes, attribute
computation functions, and predicate functions.
 Attributes, which are associated with grammar symbols (the terminal and non terminal
symbols), are similar to variables in the sense that they can have values assigned to them.
 Attribute computation functions, sometimes called semantic functions, are associated with
grammar rules. They are used to specify how attribute values are computed.
 Predicate functions, which state the static semantic rules of the language, are associated with
grammar rules.

Attribute Grammars Defined

An attribute grammar is a grammar with the following additional features:

Grammar Symbols with Attributes: In an attribute grammar, each symbol in the grammar
(like variables or operations) has associated properties called attributes. These attributes can be
either synthesized or inherited.

 Synthesized and Inherited Attributes: Synthesized attributes are used to pass


information upwards in a parse tree, while inherited attributes pass information
downwards and across the tree.
 Semantic Functions: Each grammar rule is associated with semantic functions that
compute the attribute values. These functions use the attributes of symbols involved in
the rule to determine the value of the attributes for the parent symbol.
 Dependency of Attributes: The value of synthesized attributes on a node depends only on
the values of its children nodes, while inherited attributes depend on the parent and sibling
nodes' attribute values.
 Predicate Functions: These functions help ensure correctness by checking attribute
values. If any predicate function evaluates to false, it indicates a violation of the
language's rules.
 Parse Tree and Attribute Values: A parse tree in an attribute grammar is similar to a
regular parse tree, but with attribute values attached to each node.
 Fully Attributed Tree: A parse tree is fully attributed when all attribute values have
been computed using the semantic functions.

Intrinsic Attributes:

 Synthesized Attributes of Leaf Nodes, Intrinsic attributes are a type of synthesized


attribute found at leaf nodes of the parse tree. These attributes have values determined
outside of the tree.
 Example: For instance, in a programming language, the type of a variable can be an
intrinsic attribute. This type information may come from a symbol table, which stores
variable names and types based on earlier declarations in the code.
 Initially, when we have an unattributed parse tree, the only attributes with values are the
intrinsic attributes of the leaf nodes. These values are used as starting points, and then semantic
functions are applied to compute the remaining attribute values throughout the parse tree.
 Attribute grammars help us attach properties to grammar symbols, and intrinsic
attributes are special properties, like variable types, that come from outside the parse
tree and are used to compute other attribute values.

Examples of attribute grammars:

Attribute Grammar for Ada Procedure Names:

 Syntax Rule: Describes the structure of an Ada procedure definition. It specifies that a
procedure begins with the keyword "procedure" followed by a procedure name, and ends with
the same procedure name.

 Predicate: Checks whether the name specified at the beginning of the procedure matches the
one specified at the end. This ensures consistency between the declared procedure name and its
usage.

Example:

Syntax rule: <proc_def> → procedure <proc_name>[1]

<proc_body> end <proc_name>[2];

Predicate: <proc_name>[1]string == <proc_name>[2].string


procedure myProcedureName is

begin

-- Procedure body

end myProcedureName;

Attribute Grammar for Simple Assignment Statement:

 Syntax Rule: Defines the structure of a simple assignment statement. It consists of a variable
on the left side of the assignment operator (=) and an expression on the right side.

 Expression Rule: Specifies possible expressions, which can be either a sum of two variables or
just a single variable.

 Variable Rule: Lists available variables (A, B, C) that can be used in the assignment.

 Attributes:

 actual_type: Synthesized attribute associated with variables and expressions. It stores


the actual type (int or real) of a variable or expression. For a variable, the type is
inherent, while for an expression, it's determined from the types of its components.

 expected_type: Inherited attribute linked to the expression nonterminal. It stores the


expected type (int or real) of the expression, determined by the type of the variable on
the left side of the assignment statement.

Example

The syntax portion of our example attribute grammar is

<assign> → <var> = <expr>

<expr> → <var> + <var>

| <var>

<var> → A | B | C

 In the Ada procedure example, the attribute grammar ensures that the procedure name declared
at the beginning matches the one specified at the end of the procedure definition. This
consistency check is crucial for maintaining clarity and correctness in the code.
 The attribute grammar for the assignment statement illustrates how attributes can be used to
enforce type rules. It ensures that the types of operands on both sides of the assignment match,
and that the resulting value of the expression matches the type of the variable being assigned
to.

The complete attribute grammar follows in Example 3.6.

EXAMPLE 3.6 An Attribute Grammar for Simple Assignment Statements

1. Syntax rule: <assign> → <var> = <expr>

Semantic rule: <expr>.expected_type ← <var>.actual_type

2. Syntax rule: <expr> → <var>[2] + <var>[3]

Semantic rule: <expr>.actual_type ←

if (<var>[2].actual_type = int) and

(<var>[3].actual_type = int)

then int

else real

end if

Predicate: <expr>.actual_type == <expr>.expected_type

3. Syntax rule: <expr> → <var>

Semantic rule: <expr>.actual_type ← <var>.actual_type

Predicate: <expr>.actual_type == <expr>.expected_type

4. Syntax rule: <var> → A | B | C

Semantic rule: <var>.actual_type ← look-up(<var>.string)

The look-up function looks up a given variable name in the symbol table and returns the variable’s
type.
Explanation

1. Syntax Rule: <assign> → <var> = <expr>

 This rule defines the syntax of a simple assignment statement, where a variable (<var>)
is assigned the value of an expression (<expr>) using the assignment operator =.

Semantic Rule: <expr>.expected_type ← <var>.actual_type

 This semantic rule sets the expected type of the expression (<expr>) to be the actual
type of the variable (<var>). It implies that the type of the variable must match the type
of the expression being assigned to it.

2. Syntax Rule: <expr> → <var>[2] + <var>[3]

 This rule describes an expression consisting of the sum of two variables (<var>[2] and
<var>[3]).

Semantic Rule: <expr>.actual_type ← if (<var>[2].actual_type = int) and (<var>[3].actual_type


= int) then int else real end if

 This semantic rule determines the actual type of the expression. It checks if both
variables involved in the addition are of type int. If they are, the expression is assigned
the type int; otherwise, it's assigned the type real.

Predicate: <expr>.actual_type == <expr>.expected_type

 This predicate ensures that the actual type of the expression matches its expected type,
ensuring consistency in type usage.

3. Syntax Rule: <expr> → <var>

 This rule defines an expression consisting of a single variable (<var>).

Semantic Rule: <expr>.actual_type ← <var>.actual_type

 This semantic rule sets the actual type of the expression to be the same as the actual
type of the variable.

Predicate: <expr>.actual_type == <expr>.expected_type

 Similar to the previous predicate, this ensures type consistency within the expression.

4. Syntax Rule: <var> → A | B | C


 This rule lists the possible variables (A, B, C) that can appear in the assignment
statement.

Semantic Rule: <var>.actual_type ← look-up(<var>.string)

 This semantic rule looks up the type of the variable (<var>) in the symbol table based
on its name (<var>.string). The look-up function retrieves the type associated with the
variable name from the symbol table.

A parse tree of the sentence A = A + B generated by the grammar in Example 3.6 is shown in Figure
3.6. As in the grammar, bracketed numbers are added after the repeated node labels in the tree so they
can be referenced unambiguously.

Computing Attribute Values

 The process of computing the attribute values of a parse tree, which is called
decorating the parse tree.
 If all attributes were inherited, this could proceed in a completely top-down order, from
the root to the leaves.
 Alternatively, it could proceed in a completely bottom up order, from the leaves to the
root, if all the attributes were synthesized.
 Because our grammar has both synthesized and inherited attributes, the evaluation
process cannot be in any single direction.
The following is an evaluation of the attributes, in an order in which it is possible to
compute them:

1. <var>.actual_type ← look-up(A) (Rule 4)

2. <expr>.expected_type ← <var>.actual_type (Rule 1)

3. <var>[2].actual_type ← look-up(A) (Rule 4)

<var>[3].actual_type ← look-up(B) (Rule 4)

4. <expr>.actual_type ← either int or real (Rule 2)

5. <expr>.expected_type == <expr>.actual_type is either

TRUE or FALSE (Rule 2)

The tree in Figure 3.7 shows the flow of attribute values in the example of Figure 3.6. Solid lines are
used for the parse tree; dashed lines show attribute flow in the tree.

The tree in Figure 3.8 shows the final attribute values on the nodes. In thisexample, A is defined as a
real and B is defined as an int.
Evaluation:

You might also like