0% found this document useful (0 votes)
6 views11 pages

Unit 03 CD

The document discusses Compiler Design, focusing on Context-Free Grammar (CFG) for arithmetic expressions and assignment statements, detailing the roles of syntax and semantic analysis in parsing. It explains the limitations of parsers and the necessity of semantic analysis to ensure logical correctness, alongside the use of Syntax Directed Definitions (SDD) for attribute computation. Additionally, it outlines the differences between SDD and Syntax Directed Translation (SDT), and provides examples of SDDs for arithmetic and Boolean expressions.

Uploaded by

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

Unit 03 CD

The document discusses Compiler Design, focusing on Context-Free Grammar (CFG) for arithmetic expressions and assignment statements, detailing the roles of syntax and semantic analysis in parsing. It explains the limitations of parsers and the necessity of semantic analysis to ensure logical correctness, alongside the use of Syntax Directed Definitions (SDD) for attribute computation. Additionally, it outlines the differences between SDD and Syntax Directed Translation (SDT), and provides examples of SDDs for arithmetic and Boolean expressions.

Uploaded by

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

Compiler Design

BCS-602
Instructor: Md. Shahid
Unit-03

In Context-Free Grammar (CFG), especially for arithmetic expressions, we often divide expressions into
parts like:

Non-Terminal Meaning
Expression (E) A full arithmetic expression that can have additions and subtractions (+, -)
Term (T) A part of an expression that deals with multiplications and divisions (*, /)
Factor (F) The most basic units — like identifiers (id), numbers, or parenthesized
expressions ( E )

Typical Grammar Rules for Arithmetic Expressions:


E→E+T|E-T|T // E handles addition and subtraction

T→T*F|T/F|F // T handles multiplication and division

F → (E) | id | number // F handles parentheses, identifiers, and numbers

Assignment expression grammar— It defines the rules for how an assignment statement (like x = 5)
is structured in a programming language.

Simple assignment expression grammar:

S → id = E // Assignment statement

E→E+T|T // Expression: addition or a term

T → id | num // Term: an identifier or a number


Given the following assignment expression grammar:
S → id = E // Assignment

E→E+T|T // Expressions

T → id | num // Terms

Let’s see how a parser derives the input string x = y + 10.

Parse Tree:

/|\

id = E

/|\

E + T

| |

T T

| |

id num

What the parser does:


 Checks if the input follows the grammar rules (syntax).

e.g., Is x = y + 10 in the correct format?

 Builds a parse tree or derivation.

What it doesn't check:


 Whether the variables are declared.
 Whether the types are compatible (e.g., x = true + 10 would be invalid semantically).
 Whether operations are meaningful (10 = x is syntactically fine, but semantically wrong).
 Are functions used with correct arguments?
 Are variables used within scope?

Note— Limitations of the parser are addressed by the semantic analyser (3rd phase of compiler).
Semantic Analysis
Semantic analysis is a crucial phase in the compilation process, following syntax analysis. While
parsers only check the syntax of a program (i.e., whether the program is written according to the
grammar rules), they do not verify if the program makes sense logically. This is where semantic
analysis comes in — it ensures that the program is not only syntactically correct but also
semantically meaningful, i.e., it complies with the rules of the programming language's semantics.
Problem: A parser only checks syntax, not semantics (the meaning of the code).
Analogy:

 Parsing is like checking if a sentence is grammatically correct.


 Semantic analysis checks if the sentence makes sense.

Example: int x = "Meerut"; → Syntax valid, but semantically wrong because we cannot
assign a string value to an integer variable.

Solution: Need attributes (e.g., type, val) and rules to enforce meaning.

Let's look at the expression: a = b + 10

Checks Needed:

1. Are a and b declared?


 Symbol Table Lookup: We need to verify that both a and b have been declared
previously in the program. If either a or b is undeclared, it will result in a semantic
error.
2. Are b and 10 compatible types?
 The type of b must be compatible with 10. For instance, if b is an integer, 10 is an
integer, so they are compatible. If b is a string, then this would be a semantic error
because we cannot add an integer to a string.
3. What’s the result’s type?
 The result of b + 10 should have a defined type. If b is an integer, the result would
also be an integer. If b is a float, the result would be a float. We need to ensure
that the result type is properly inferred and compatible with the type of a.
How We Automate These Checks:

 We use a mechanism called Syntax Directed Definition (SDD).


 In SDD, we attach semantic rules and attributes (like type) to the grammar rules
of the parser.
 As the parser builds the parse tree, it simultaneously checks meaning-related
constraints using these attributes.

Syntax Directed Definition (SDD): A syntax-directed definition (SDD) is a context-free


grammar together with attributes and rules. Attributes are associated with grammar
symbols (terminals/non-terminals) and rules are associated with productions. If X is a
symbol and a is one of its attributes, then we write X.a to denote the value of a at a
particular parse-tree node labelled X. SDDs extend a CFG by adding semantic
information (attributes/rules) without altering the grammar’s structure.

SDD = CFG + Semantic Information

Q. Consider the following expression grammar:


E→E+T|T

T --> T * F| F
F → num
(a) Write a Syntax-Directed Definition (SDD) to compute the value of an arithmetic
expression based on the given grammar.
(b) Using the SDD, draw the annotated parse tree for evaluating the expression 3 + 2 * 5.
Answer— a. SDD

Production Semantic Rules


E → E₁ + T E.val = E₁.val + T.val
E→T E.val = T.val
T → T₁ * F T.val = T₁.val * F.val
T→F T.val = F.val
F → num F.val = num.lval
b. Annotated Parse Tree –

3+2*5 E = 13 ( answer )

E.val= 3 + T.val=10

T. val= 3 T. val = 2 x F. val=5

F. val= 3 F. val=2

num (3) num (2) num (5)

Attributes: These are metadata attached to grammar symbols (like E, T, id) to store
computed information (e.g. type, value, scope) during semantic analysis. They are defined
in SDD using semantic rules. Attributes may be of any kind: numbers, types, table
references, or strings.
Two Major Types of Attributes

1. Synthesized Attributes: Computed from the children nodes' attributes in the parse tree.
Example:
If we have a rule:
Production Semantic Rule
E → E₁ + T E.value = E₁.value + T.value
Here, E.value is synthesized because it is computed from E₁.value and T.value. The parent’s
attribute (E.value) depends on its children’s attributes (E₁.value and T.value) in the parse tree.
2. Inherited Attributes: Inherited attributes pass information from a parent node or left sibling
to a child node. Such attributes pass type information, scope information, function parameter
types, etc.
Example: production: A → B C
Semantic Rules:
1. B. i = A. i [ The inherited attribute i of B is assigned the value of i from its parent node A.]
2. C. i = B.s [ The inherited attribute i of C is assigned the value of s from its left sibling B.]

Q. In Syntax-Directed Definitions (SDDs), what are the two main types of attributes
used to propagate semantic information? Give one example of each type.

Types of SDD
SDDs are classified into two main types based on attribute dependency flow:

1. S-attributed SDD: An SDD where all attributes are synthesized (computed from
children to parents).

Key Features:

 Bottom-up evaluation: Works naturally with LR parsers (e.g., Yacc/Bison).


 No inherited attributes: All data flows upward in the parse tree.

Example: E → E + T E.val = E₁.val + T.val // Synthesized only

T→F T.val = F.val


F → num F.val = num.value

Use Case: Simple arithmetic expression evaluation.

2. L-Attributed SDD: An SDD where attributes can be:

 Synthesized (child → parent),


 Inherited (parent → child or sibling → sibling),
 But dependencies must flow left-to-right in the parse tree.
 L-attributed SDDs are compatible with top-down parsers like LL(1).
Note— In Syntax-Directed Definitions (SDDs), unless specified otherwise, we typically
assume that attributes of non-terminals on the right-hand side (RHS) of a production are
synthesized unless they are explicitly given an inherited dependency.

Q: Consider the following Syntax-Directed Definition (SDD):

Production:

A→BC

Semantic Rules:

1. A.s = B.b

2. B.i = f(C.c, A.s)

Explain why this SDD is not L-attributed.

Answer—

This SDD is not L-attributed because the inherited attribute B.i depends on C.c (a right
sibling in the production A → B C).

Key Violation:

In L-attributed SDDs, an inherited attribute (like B.i) can only depend on:

 Inherited attributes of the parent (A)


 Attributes of left siblings (none here, since B is first)

Since B.i = f(C.c, A.s) requires C.c (a right sibling), it breaks the left-to-right evaluation
rule of L-attributed definitions.

Result:

 L-attributed SDDs must allow dependencies in a strict left-to-right order.


 Here, B.i needs C.c (which hasn’t been computed yet), making it impossible to
evaluate in a single pass.

Thus, the given SDD is not L-attributed.


Q. Consider the following two sets of semantic rules:
Rule 1:
Production: A → PQ
Semantic rules:

 P.i = A.i + 2
 Q.i = P.i + A.i
 A.s = P.s + Q.s
Rule 2:
Production: A → XY
Semantic rules:

 X.i = A.i + Y.s


 Y.i = X.s + A.i
Which of the above rules defines an L-attributed SDD? Justify your answer.

Answer—
Rule 1 Analysis:
Production: A → PQ
Semantic rules:
P.i = A.i + 2 → P inherits from parent A. (Allowed in L-attributed)

Q.i = P.i + A.i → Q inherits from left sibling P and parent A. (Allowed in L-attributed)
A.s = P.s + Q.s → A synthesizes from children P and Q. (Always allowed)
Conclusion: Rule 1 is L-attributed.
Rule 2 Analysis:
Production: A → XY

Semantic rules:
X.i = A.i + Y.s
Here, X is depending on Y.s (right sibling Y). It is not allowed in L-attributed SDD (inherited
attributes should depend only on parent or left siblings, not right siblings).
Y.i = X.s + A.i
Y depends on X.s (left sibling X) and parent A. (Allowed)

Conclusion: Rule 2 is NOT L-attributed.


Final Answer: Only Rule 1 defines an L-attributed SDD.

Q. Differentiate between Syntax-Directed Definitions (SDD) and Syntax Directed Translation (SDT)
with one key point each.

Answer: Syntax-Directed Definition (SDD) associates semantic rules with grammar


productions but keeps them separate from the grammar structure. In contrast, Syntax-
Directed Translation (SDT) embeds semantic actions directly within grammar rules using curly
braces { }. SDD is typically used for computing attributes after or alongside parsing, often
during annotated parse tree traversal. On the other hand, SDT enables actions to be executed
immediately during parsing, making it suitable for real-time translation tasks. Thus, while the
parser ignores SDD rules, it actively executes SDT actions.

Q. Write syntax directed definition for the given assignment statement used for expression
evaluation:

S → id = E

E→E+E

E→E*E

E → (E)

E → id

Answer:

Production Semantic Rule


S → id = E S.val = E.val
E→E+E E.val = E₁.val + E₂.val

E→E*E E.val = E₁.val * E₂.val

E → (E) E.val = E₁.val

E → id E.val = lookup(id.lexeme) It means “fetch id's


value from symbol table”.

Note— This SDD is used to compute values only.


Q. Define an SDD with attributes to support three-address code generation for Boolean
expressions.

Or
Write SDD to produce three-address code for Boolean expressions.

Or
Write down SDD of three-address code for Boolean expressions.
Or

Write an SDT to produce three-address code for Boolean expressions.

Answer: B, B₁, and B₂ are non-terminals in the grammar (they can be expanded further).

Example:
B₁ might expand to (x > 0).
B₂ might expand to (y < 10).
B becomes (x > 0) || (y < 10).

Production Semantic Rule


B -- > B1 || B2 ( OR operation ) B1. true = B.true
B1. false = newlabel()
B2. true = B.true
B2. false= B.false
B. code = B1. code || label( B1. false)|| B2.code
B -- > B1 && B2 ( AND operation ) B1.true = newlabel()
B1 . false = B. false
B2 . true = B.true
B2. false = B.false
B. code = B1. code || label( B1. false)|| B2.code
B -- > ! B1 ( NOT operation ) B1. True = B. false
B1. false = B. true
B. code = B1 . code
B -- > true ( Terminal case ) B.code = gen(‘goto’ B.true)
B -- > false ( Terminal case ) B.code = gen( ‘goto’ B.false)
Note – Three-Address Code (TAC) is an intermediate representation (IR) used by compilers to simplify
complex expressions into a sequence of simpler instructions, each involving at most three operands—
typically two source operands and one destination. It introduces temporary variables to break down
computations and makes control flow explicit using labels and jumps. As a machine-independent form,
TAC allows compilers to perform various optimizations without being tied to specific hardware. Being
positioned between high-level source code and low-level machine code, IR like TAC plays a crucial role in
code analysis, optimization, and generation.

Boolean Expression— It is a logical statement that evaluates to either true or false. Example: (5
> 3) → true, (10 == 20) → false

Note – This PDF covers only the ST2 syllabus. Complete notes for Unit 3 will be provided after
ST2 concludes.

You might also like