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 worksBefore ANSI C prototypes, calling foo(1, 2, 3) when foo expected two ints was undefined behavior. Clang's Sema checks arity and parameter types on every call. The Linux kernel builds with -Werror=implicit-function-declaration because signature mismatches cause real production bugs.
Look up the function in the symbol table. Verify argument count equals parameter count. For each position, verify the argument type is compatible with the parameter type, applying permitted coercions (e.g., int to float).
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 implement function signature checking that validates argument count and types at call sites. This exercise requires storing signatures in your symbol table and comparing each call against the declared parameter list.
Check every function call against the callee's declared signature: the right number of arguments, and argument types that are either identical to the parameter type or safely widened to it.
One item per line; blank lines are ignored.
;:
Types arecLoading…
char, int, float and (return type only) void. () or (void) means no parameters. Declarations may appear anywhere; a call can only use functions declared on an earlier line.NAME(ARG, ARG, ...). An argument is
42) → int2.5) → float'a') → char| From → To | Result |
|---|---|
| same type | ok |
char → int, char → float, int → float | ok (widening) |
float → int, float → char, int → char | error: narrowing |
void → anything | error: a void value cannot be an argument |
For each call line (L = 1-based line number in the input), check the call and all nested calls. Report errors in this order: nested calls first (left to right, innermost first), then the call's own problems:
cLoading…
With an argument-count mismatch, don't check argument types for that call. A call to an undefined function has type int wherever it is used (so its caller can still be checked), and its arguments are still checked for nested problems.
If a call line produced no errors at all, print instead:
cLoading…
listing the argument types as written (before widening). Finish with calls=C errors=E, counting call lines and error lines.
Input:
cLoading…
Output:
cLoading…
check_call() that returns the call's type and reports problems.Hidden tests cover (void) and zero-argument calls, nested calls (including void results used as arguments), calls before their declaration, and several errors on one line.