This content originally appeared on DEV Community and was authored by Lahari Tenneti
After statements, we will now be adding support for logical operators and control flow statements – conditional (if-else) and looping (while, for).
What I built: Commit 089ad4d
What I understood:
1) If Statements
- We extend the
statementrule to accomodateifStmt, which leads toexpression(). ThethenBranchcallsstatement()again. - Also, we avoid the dangling-else problem, wherein nesting-if conditions cause uncertainty about which
ifstatement anelseclause belongs to – inner or outer? - This is by checking for the existence of an
elsebranch which is assumed to belong to the innermostifstatement.
2) Logical Operators
- We modify the grammar to have
assignment()callor()(which callsand()) instead ofequality().equality()is called byand() - We use short-circuiting while using logical-operators, which makes decisions basis the state of the left-operand.
- Ex: In
OR, if the left operand is truthy (evaluates to true), the interpreter skips the right operand, and returns the left operand itself. - But if the left-operand is
false, it has to check the right operand and compute the result based on it.
var greet = greeting or "Hello";
//defaults to Hello if greeting is null/false.
- In
AND, if the left-operand isfalse, the entire expression results infalse, and thus the second operand needn’t be evaluated.
//LOGIC
public Object visitLogicalExpr(Expr.Logical expr) {
Object left = evaluate(expr.left);
if (expr.operator.type == TokenType.OR) {
if (isTruthy(left)) return left;
} else {
if (!isTruthy(left)) return left;
}
return evaluate(expr.right);
}
3) While Loops
- The
statementrule is further extended to callwhileStmt, which basically executes the body of statements if the given condition evaluates to ‘true’
//LOGIC
public Void visitWhileStmt(Stmt.While stmt) {
while (isTruthy(evaluate(stmt.condition))) {
execute(stmt.body);
}
return null;
}
4) For Loops
-
forStmtis added to thestatementrule. A for condition is supposed to have three parts – initialiser, the condition, and the action (increment/decrement). Variables are created to hold these three parts. - Interestingly, we don’t evaluate a
forloop as aforloop, and actually convert it into awhileloop - We first check for the initialiser by looking for
VARand callvarDeclaration()if it’s present. - Then, the interpreter looks for a
;, after which it callsexpression(). Finally, we callexpression()again on encountering an increment/decrement. - The statements are wrapped inside a block, as a list.
- We also append the increment condition to the body of statements.
- When then wrap this body into a
whileloop, that is executed after the initialiser statement runs exactly once.
for (var i = 0; i < 10; i = i + 1) print i;
is converted to
var i = 0; // Initialiser runs once
while (i < 10) {
// the parser here groups the original body of statements and the
increment into a single unit for the while loop’s body
{
print i;
i = i + 1;
}
}
What’s next:
Functions! This takes the interpreter ahead significantly by introducing concepts like lexical scope, closures, call stack management, and a return mechanism.
Musings:
Coffee Cold is a song I deeply love. For some reason, it feels like both a dig at and a celebration of life’s strangeness. Like it’s trying to tell me that at the end of the day, there are things way beyond my control that shape my world. I can either choose to get upset due to them or smile and walk on, towards my next adventure. “Life is neither a Tempest, nor a Midsummer Night’s Dream. It’s more like a Comedy of Errors and you take it As You Like It.” As the Tao Te Ching says, it’s alllll about the flow. 
This content originally appeared on DEV Community and was authored by Lahari Tenneti



