Master the fundamental concepts of semantic analysis through this focused micro-challenge.
Three hints are available for this task, revealed one at a time inside the code workspace so you can struggle productively before seeing them.
Every task includes starter code, theory, and hidden tests so you can implement and verify locally in the browser.
How it worksTypeScript reports used before its declaration; C warns on implicit declarations. OpenSSL once shipped bugs from calling functions that were never declared. The fix is a two-pass or ordered walk: process declarations before uses in each scope, or reject forward references where the language forbids them.
Maintain a set of declared names per scope. On declaration, insert with line number. On use, verify the name exists and that the declaration line precedes the use line. Distinguish undefined (never declared) from use-before-decl (declared later).
cLoading…
Production compilers embed this step inside a longer pipeline. GCC flows through cpp, cc1, assembly, and ld; Clang uses the driver, Sema, LLVM IR passes, and a target backend. LLVM bitcode, JVM bytecode, and WASM are other familiar IRs at the same layer. The exercise isolates one pass so you can test it alone before chaining it to the next stage.
You will detect variables used before declaration and references to undefined names. This exercise asks you to walk simple statements, maintain a declaration table, and emit precise errors with line numbers.
Find every use of a variable that is not in scope, and tell the programmer why: either it is declared, but only later (a use before declaration), or no visible declaration exists at all (undefined).
A small block-structured program, one statement per line (blank lines ignored):
| Line | Meaning |
|---|---|
int NAME; / int NAME = EXPR; | declaration (also char, float) |
NAME = EXPR; | assignment |
return EXPR; | return |
{ / } | open / close a nested block |
An EXPR is made of identifiers, integer literals, + - * / ( ) and spaces. Everything outside any { } is the global scope.
int x = x + 1; uses x before its declaration.For each identifier in an assignment target or an expression, in order of appearance (left to right, line by line):
line L: 'NAME' used before declaration (declared at line D), where D is the first such later declaration;line L: undefined variable 'NAME'.Finish with uses=U errors=E, where U counts every identifier use checked (declared names on the left of a declaration are not uses).
Input:
cLoading…
Output:
cLoading…
step on line 7 is undefined: its declaration was inside a block that has closed.
{ and popped on }.Hidden tests cover shadowing across blocks, deeply nested blocks, globals declared after use, and names that are only declared in sibling blocks.