CSS Prepare

optional · CSS study notes

II.4 Components of a Programming Language

⬆️ P-I.II. Programming Fundamentals · Question Bank · Chapter II (2016–2026)

🧠

Remember: Tokens are words; syntax is grammar; semantics is meaning.

Start here — what you should be able to do

  • Classify identifiers, literals, keywords, operators and punctuation.
  • Separate syntax, static semantic checks and logic errors.
  • Read a simple grammar rule and explain precedence.

Reading order: foundation checks → full notes and examples → exam traps → self-test without notes → past-paper answers. All sections below remain part of the topic; code examples are kept in full.

Foundation checks

Three different kinds of mistake

KindExampleWhat it means
Syntaxint x = ;The token arrangement violates the grammar.
Static semantic/type errorUsing an undeclared variableThe form may parse, but names/types are invalid.
Logic errorAdding when multiplication was requiredLegal code solves the wrong problem.

Do not equate all semantics with logic errors: compilers check many semantic constraints. Comments and whitespace: normally carry no runtime operation, but they separate tokens; removing them carelessly can change the program. Grammar: BNF defines valid forms; a grammar is not automatically unambiguous.

1. Core Concepts

  • Syntax: the formal rules governing how valid statements are constructed (the grammar of the language). A compiler checks syntax first — a syntax error stops compilation entirely.
  • Semantics: the meaning/behavior associated with syntactically valid statements. Static semantic rules include name and type checks; dynamic semantics describes execution. Logic errors are a separate failure to solve the intended problem.
  • Tokens: the smallest meaningful units the compiler recognizes — every program is broken into tokens before parsing. Categories:
    • Keywords: reserved words with fixed meaning (int, if, return, class) — cannot be redefined or used as identifiers
    • Identifiers: programmer-defined names for variables, functions, classes, etc.
    • Literals/Constants: fixed values written directly (42, 3.14, 'x', "text", true)
    • Operators: symbols performing operations (arithmetic, relational, logical, bitwise, assignment)
    • Punctuators/Separators: symbols that structure code without performing computation (;, ,, { }, ( ), [ ])
  • Comments: non-executable annotations for humans; replaced during translation, with token separation preserved

2. Syntax vs Semantics — Example

int x = 5 / 0;
  • Syntactically valid — this line parses fine, follows all grammar rules
  • Semantically problematic — division by zero is undefined behavior/runtime error, even though the syntax is correct

Contrast with:

int x = 5 0;
  • This is a syntax error — missing an operator between 5 and 0; the compiler rejects it before it can even consider meaning

3. Grammar and Rules

  • Every language defines its syntax formally, often using grammar notations like BNF (Backus-Naur Form), which the compiler's parser uses to validate structure
  • A statement must be well-formed (follows the grammar) to compile; it must additionally be meaningful in context (e.g. correct types) to behave as intended

4. 💻 Code Examples: C & C++

The syntax-vs-semantics example from above, made runnable, plus tokens labelled:

C:

#include <stdio.h>
int main(void) {
    int x = 5 / 2;       /* syntactically valid; semantics: integer division -> 2 */
    // int y = 5 0;       // would be a SYNTAX error -- missing operator, won't compile
    printf("%d\n", x);    // tokens: printf ( "%d\n" , x ) ;
    return 0;
}

C++:

#include <iostream>
using namespace std;
int main() {
    int x = 5 / 2;        // syntactically valid; semantics: integer division -> 2
    // int y = 5 0;        // would be a SYNTAX error
    cout << x << endl;      // tokens: cout << x << endl ;
    return 0;
}
  • int, return are keywords; x, main are identifiers; 5, 2 are literals; /, << are operators; ;, (, ) are punctuators — every one of these is a token

5. MCQ Traps

  • Error distinction: syntax and static semantic errors can be diagnosed during translation; logic errors are defects in the intended algorithm.
  • Keywords are part of the language's fixed vocabulary; identifiers are chosen by the programmer — a keyword can never double as an identifier
  • Punctuators (like ; or {}) are tokens too, but they don't perform operations the way operators do
  • Comments carry no runtime operation; they are replaced during translation and can separate tokens. Do not remove token-separating comments without whitespace.

6. ✅ Self-Test Questions (with Answers)

Q1. Differentiate syntax from semantics with one example each.

Answer

  • Syntax: rules for arranging tokens into valid statements; the parser checks these rules.
  • Static semantics: names, types and other contextual constraints; many are checked by the compiler.
  • Dynamic meaning: what valid code does during execution.
  • Logic error: valid code fails the programmer's intended task; testing and tracing are needed.
  • Example: a missing semicolon is syntax; an undeclared name is a static semantic error; using the wrong formula is logic.
// SYNTAX ERROR -- breaks the grammar; the compiler rejects it
// int x = 5 0;      // no operator between 5 and 0 -> will not compile
// if (a > b         // missing ) and ;              -> will not compile

// SEMANTIC / LOGIC ERROR -- grammatically perfect, meaning is wrong
int length = 5, width = 3;
int area = length + width;   // legal C++, but the formula should be *
cout << area;                // prints 8; the correct area is 15
AspectSyntaxSemantics
ConcernsForm / structure of statementsMeaning / behaviour of statements
Checked byParser during translationStatic semantic checks by compiler; intended behaviour by reasoning/testing
On violationSyntax diagnosticMay be a type diagnostic, invalid runtime operation, or logic defect
Typical errorMissing ; , unbalanced bracesWrong operator or formula, wrong condition

MCQ trap: if (x = 5) is semantically wrong, not syntactically — = is a legal assignment whose result (5) is non-zero, so the condition is always true; the intended test was ==. Similarly int x = 5 / 2; is valid syntax whose semantics give 2, because integer division truncates the fractional part.

Q2. List the five categories of tokens found in a typical high-level language.

Answer — key points

  • A token is the smallest unit of a program meaningful to the compiler, produced by the lexical analyser as it scans the source text.
  • Every C/C++ program reduces to a stream drawn from exactly five categories:
#CategoryDescriptionExamples
1KeywordsReserved words with fixed meaning; cannot be redefinedint, if, while, return, class, void
2IdentifiersProgrammer-chosen names for variables, functions, classestotal, main, studentAge, _count
3Constants / LiteralsFixed values written directly in the code42, 3.14, 'x', "text", true
4OperatorsSymbols that perform an operation on operands• - * / % == && ! << ++
5Punctuators / SeparatorsStructure the code without computing anything; , ( ) { } [ ] #
if (count == 10) total += price;
// if      -> keyword
// count, total, price -> identifiers
// ==, +=  -> operators
// 10      -> literal
// ( ) ;   -> punctuators
// 11 tokens in total
  • Lexical detail: comments/whitespace generally carry no runtime operation, but can separate tokens; removing them carelessly can change tokenisation.

Q3. Why is 5 0; (missing operator) a syntax error while 5/0; is not?

Answer

  • 5 0; fails the grammar because the literals have no operator between them.
  • 5 / 0; has a valid expression form, but integer division by zero has undefined behaviour if evaluated.
  • A compiler may diagnose a constant zero divisor; do not promise that compilation succeeds or that execution must crash.
  • Key distinction: grammatical validity does not establish a valid operation or correct algorithm.
Aspect5 0;5 / 0;
Fault typeSyntax (grammar) errorSemantic / run-time error
Detected atCompile time, by the parserRun time (integer division by zero)
Translation outcomeSyntax diagnosticDepends on context/diagnostics; evaluation is not valid
Grammar rule matched?None existsexpression -> literal / literal
// int a = 5 0;     // SYNTAX ERROR: "expected ';' before numeric constant"
int b = 5 / 0;      // compiles; crashes at run time (UB)
int z = 0;
int c = 5 / z;      // also compiles -- the compiler cannot always even warn

double d = 5.0 / 0.0;   // NO crash: prints inf (IEEE-754 floating point)
  • MCQ trap: integer division by zero is undefined behaviour and normally aborts the program, but floating-point division by zero is well defined under IEEE-754 and yields inf, -inf or nan — so 5/0 and 5.0/0.0 behave completely differently.
  • A modern compiler may warn about a literal 5/0, but a warning is not a syntax error and compilation still succeeds.

Q4. What role does a formal grammar (e.g. BNF) play in defining a language's syntax?

Answer — key points

  • A formal grammar gives a language's syntax a precise, mathematical definition instead of an informal English description, removing all ambiguity about what counts as a legal program.
  • BNF (Backus–Naur Form) — devised for ALGOL 60 by John Backus and Peter Naur — expresses the grammar as a set of production rules over non-terminals (\<expression>) and terminals (literal symbols such as + or ;).
  • The compiler's parser (syntax analyser) uses these rules directly to check whether the token stream from the lexical analyser can be derived from the start symbol
  • if it can, a parse tree is built, and if it cannot, a syntax error is reported.
<statement> ::= <if-stmt> | <assignment> | <block>
<if-stmt>   ::= "if" "(" <expression> ")" <statement>
              | "if" "(" <expression> ")" <statement> "else" <statement>
<assignment>::= <identifier> "=" <expression> ";"
<expression>::= <term> | <expression> "+" <term>
<term>      ::= <factor> | <term> "*" <factor>

Its main uses are:

  • Unambiguous specification — the language standard says exactly what is legal, so independent compiler vendors agree
  • Automatic parser generation — tools such as yacc/bison and ANTLR build a parser straight from the grammar
  • Encoding precedence and associativity — note above how \<term> sits beneath \<expression>, which is why * binds tighter than + in 2 + 3 * 4 (result 14, not 20)
  • Extensions — EBNF adds { } for repetition, [ ] for optional parts; syntax (railroad) diagrams are the graphical equivalent
  • MCQ trap: a grammar defines syntax only, never semantics — x = 5 / 0; is perfectly derivable from the grammar above, so the parser accepts it; the failure appears at run time.
  • Meaning is specified separately (by attribute grammars, denotational semantics or prose in the standard), which is why a compiler catches missing semicolons but not wrong formulas.

Recall check and coverage

  • Explain the three learning outcomes at the top without looking.
  • Reproduce one example or trace and test a boundary case.
  • Answer each self-test, then compare with the key.
  • Attempt each recorded past-paper task on this page.

Recorded written references: No direct written record in this topic's current notes. These concepts support the chapter's programming questions.

Evidence limit: this page preserves the question records found in your Notion notes. Disputed labels and questions not checked against original PDFs remain flagged in the Question Bank; this is not a claim of exhaustive original-paper verification.