Back to the journal

Project notes / 2 MIN READ

Compiler design makes boundaries concrete

Parsing, meaning, and execution become easier to reason about when they are separate.

Sai Sri Harsha Guddati ·

My compiler-design project explores a Delphi-Pascal interpreter using Java and ANTLR. It is a useful counterweight to work with probabilistic systems: the language has explicit structure, and the implementation has to decide what that structure means.

The part I find especially interesting is the separation between parsing a program and executing it.

A parse is not an interpretation

An expression can be syntactically valid while referring to an undefined name or applying an operation to an inappropriate value. Recognizing the grammar is only one stage.

An ANTLR parse tree gives the program a structure the visitor can inspect. My public implementation evaluates that parse tree directly rather than building a separate AST. Name resolution, type rules, and execution semantics can then be considered without treating the source as an undifferentiated string.

This separation makes failures more precise. “Unexpected token” and “undefined variable” describe different problems and should lead to different explanations.

Small programs expose large choices

An illustrative assignment looks simple until scope becomes involved. Does a name refer to the local environment or an outer one? What happens when a declaration shadows another? When is a value read, and where is an update stored?

Arithmetic introduces another set of choices: value types, conversion rules, and errors. Control flow brings questions about evaluation order and termination.

These are not obscure implementation details. They determine the meaning of the program the user wrote.

Carry the lesson elsewhere

The same habit is useful in API design and AI workflows. Parse the input, validate its structure, establish its meaning, then decide what may execute. Each stage should have a contract and a useful error.

A tool call encoded as JSON still needs interpretation. A retrieved passage still needs context. A valid configuration still needs domain rules.

Compiler work makes those boundaries concrete because the implementation cannot rely on a persuasive explanation to cover an ambiguous rule. It must choose and implement a behavior.

I value projects that train this kind of precision. An interpreter is not only a way to execute a language. It is a way to practice turning an idea into explicit semantics, one small program at a time.

More from the journal