Expressions and Statementshttps://courses.missouristate.edu/anthonyclark/333/
Outline
Topics and Learning Objectives• Discuss how statements can be parsed and evaluated
Assessments• None
Expressions and Statements
As a reminder, we can broadly state that
• Expressions are lines of code that return a result
• Statements are lines code that do not return a result
1 + 5 // returns 66 * (1 – 3 – 5) // returns -42x > y ? ”hi” : “there” // return “hi” or “there”
x = 1 + 5y = 6 * (1 – 3 – 5) z = x > y ? ”hi” : “there” Note, in some languages (like
C++) the assignment statement returns the value.
Expressions
• So far, we’ve focused on parsing expressions• Our arithmetic grammar is:
• But how do we handle statements?• Something like this:
x = 1 + 2
add_sub : mul_div ( ('+' | '-') mul_div )*;
mul_div : atomic ( ('*' | '/') atomic )*;
atomic : Identifier | Number | '(' add_sub ')';
Slightly More Complete Grammarprogram : statement*;statement : initialization | assignment | if_statement | block;
initialization : 'let' Identifier '=' expression ';';assignment : Identifier = expression ';';
if_statement : 'if' expression block 'else' block;
block : '{' statement* '}’;
expression : add_sub | etc;add_sub : mul_div (('+' | '-') mul_div)*;mul_div : atomic (('*' | '/') atomic)*;atomic : Identifier | Number | '(' add_sub ')';
Slightly More Complete Grammar (Pruned back)program : statement*;statement : initialization | assignment | if_statement | block;
initialization : 'let' Identifier '=' expression ';';assignment : Identifier = expression ';';
if_statement : 'if' expression block 'else' block;
block : '{' statement* '}’;
expression : add_sub | etc;add_sub : mul_div (('+' | '-') mul_div)*;mul_div : atomic (('*' | '/') atomic)*;atomic : Identifier | Number | '(' add_sub ')';
Slightly More Complete Grammar (Pruned back)program : statement*;statement : initialization | assignment | if_statement | block;
initialization : 'let' Identifier '=' expression ';';assignment : Identifier = expression ';';
if_statement : 'if' expression block 'else' block;
block : '{' statement* '}’;
expression : add_sub | etc;add_sub : mul_div (('+' | '-') mul_div)*;mul_div : atomic (('*' | '/') atomic)*;atomic : Identifier | Number | '(' add_sub ')';
Slightly More Complete Grammar (Pruned back)
program : statement*;
statement : assignment;
assignment : Identifier = expression ';';
expression : add_sub;
add_sub : mul_div (('+' | '-') mul_div)*;
mul_div : atomic (('*' | '/') atomic)*;
atomic : Identifier | Number | '(' add_sub ')';
Slightly More Complete Grammar (Pruned back)
program : statement*;
statement : assignment;
assignment : Identifier = expression ';';
expression : add_sub;
add_sub : mul_div (('+' | '-') mul_div)*;
mul_div : atomic (('*' | '/') atomic)*;
atomic : Identifier | Number | '(' add_sub ')';
Slightly More Complete Grammar (Pruned back)
program : assignment*;
statement : assignment;
assignment : Identifier = add_sub ';';
expression : add_sub;
add_sub : mul_div (('+' | '-') mul_div)*;
mul_div : atomic (('*' | '/') atomic)*;
atomic : Identifier | Number | '(' add_sub ')';
Slightly More Complete Grammar (Pruned back)
program : assignment*;
assignment : Identifier = add_sub ';';
add_sub : mul_div (('+' | '-') mul_div)*;
mul_div : atomic (('*' | '/') atomic)*;
atomic : Identifier | Number | '(' add_sub ')';
Slightly More Complete Grammar (Pruned back)
program : assignment*;
assignment : Identifier = add_sub ';';
add_sub : mul_div (('+' | '-') mul_div)*;
mul_div : atomic (('*' | '/') atomic)*;
atomic : Identifier | Number | '(' add_sub ')';
x = 5;y = x + 5;
program
assignment
ID(x) = add_sub ;
mul_div
atomic
NUM(5)
assignment
ID(y) = add_sub ;
mul_div
atomic
ID(x)
mul_div
atomic
NUM(10)
+
program : assignment*;
assignment : Identifier = add_sub ';';
add_sub : mul_div (('+' | '-') mul_div)*;
mul_div : atomic (('*' | '/') atomic)*;
atomic : Identifier | Number | '(' add_sub ')';
x = 5;y = x + 5;
Parse Tree
program
assignment
ID(x) = add_sub ;
mul_div
atomic
NUM(5)
assignment
ID(y) = add_sub ;
mul_div
atomic
ID(x)
mul_div
atomic
NUM(10)
+
program : assignment*;
assignment : Identifier = add_sub ';';
add_sub : mul_div (('+' | '-') mul_div)*;
mul_div : atomic (('*' | '/') atomic)*;
atomic : Identifier | Number | '(' add_sub ')';
x = 5;y = x + 5;
Parse Tree ASTprogram
=
x 5
=
+
x 10
y
program
assignment
ID(x) = add_sub ;
mul_div
atomic
NUM(5)
assignment
ID(y) = add_sub ;
mul_div
atomic
ID(x)
mul_div
atomic
NUM(10)
+
program : assignment*;
assignment : Identifier = add_sub ';';
add_sub : mul_div (('+' | '-') mul_div)*;
mul_div : atomic (('*' | '/') atomic)*;
atomic : Identifier | Number | '(' add_sub ')';
x = 5;y = x + 5;
Parse Tree ASTprogram
=
x 5
=
+
x 10
y
This is what we’ve coded so far.
How do we represent this in Rust?
• We used an Enum to represent expressions.
• We did so because we can have multiple types of expression nodes (Addition, Subtraction, Number, etc.).
• We will only have one type of statement node (Assignment).
• But we are still going to use an Enum (so that we can add other types of nodes later on—we won’t have time to do so for an assignment).
Convert Grammar Into Source Code
1. Each rule defined in the grammar becomes a function/method2. References to that rule become a function call3. The body of a rule function follows the flow of the rule’s RHS4. Alternatives (a1 | a2 | …) are handled with branches (if-then-else, switch
statements, match expressions, etc.)5. An optional grouping (…)* becomes a while loop that can loop zero or
more times6. Epsilon transitions enable a function to return without doing anything7. Each reference to a terminal (token) requires you to check that the
current token is correct, and then either report an error or advance to the next token
These steps do not change for statements!
Expressions and Statements
#[derive(Debug)]enum ExprASTNode {
Addition(Box<ExprASTNode>,Box<ExprASTNode>
),Subtraction(
Box<ExprASTNode>,Box<ExprASTNode>
),Multiplication(
Box<ExprASTNode>,Box<ExprASTNode>
),Division(
Box<ExprASTNode>,Box<ExprASTNode>
),Number(f64),
}
#[derive(Debug)]enum StmtASTNode {
Assignment(Name(String),ExprASTNode
),}
Why do we not need to Box the ExprASTNode?
What is the size of an ExprASTNode?
Representing an entire program AST
• Our programs comprise individual assignment statements• So, our program is a list/array/vector of StmtASTNode• In code:
let mut program: Vec<StmtASTNode> = Vec::new();
Jay
See Jay for a slightly more complete version.
https://gustavus.edu/mcs/max/courses/S2006/MCS-287/