Start by clarifying the language's grammar and semantics, then design a clean architecture (lexer, parser, evaluator) that separates concerns and is easily extensible. Implement the core features incrementally, testing each component, and structure the evaluator with a visitor pattern or dispatch table to simplify adding conditionals, loops, and functions later.
Pro tip: Emphasize extensibility from the start: use an AST with distinct node types and a visitor pattern, so adding new language constructs requires minimal changes to existing code. Also, discuss how you would test each component and handle errors gracefully.
Ask clarifying questions about the language syntax, supported operations, error handling, and performance expectations. Define a minimal but complete grammar for the core features.
Outline a modular design: lexer to tokenize input, parser to build an AST, and an evaluator to execute the AST. Choose data structures (e.g., environment for variables) and patterns (e.g., visitor) that support extension.
Code the lexer, parser, and evaluator for assignment, arithmetic, and print. Use recursive descent parsing for simplicity and an environment map for variable storage.
Write unit tests for each component and integration tests for sample programs. Ensure error cases (e.g., undefined variables, syntax errors) are handled gracefully.
Explain how to add conditionals, loops, and functions: extend the grammar, add AST nodes, and update the evaluator with new visit methods. Discuss potential challenges like scoping and control flow.
AI-generated suggestions, not part of the candidate's original notes. May be inaccurate — verify before relying on them.