Grammar & Syntax
Writing down what a valid program looks like: productions, derivations, EBNF, and the ambiguity that precedence and associativity exist to resolve.
A grammar is a finite set of rules that decides an infinite set of token sequences. Writing one down separates "what is a legal program" from "how do I recognise one", and that separation is the reason a language can have more than one implementation.
A derivation is the proof that a token sequence is in the language. Leftmost and rightmost derivations are the two canonical orders, and they are exactly the orders that top-down and bottom-up parsers reconstruct.
Two notations for the same grammars. EBNF adds repetition, option and grouping operators that remove the recursion boilerplate — and in doing so, quietly stops telling you which way a list associates.
One nonterminal on the left-hand side, and no ability to look at the surroundings. That single restriction is what makes efficient parsing possible — and what makes "declared before use" someone else's problem.
A grammar is ambiguous when one token sequence has two parse trees. `1 + 2 * 3` reading as both 9 and 7 is the toy case; the dangling `else` is the one that shipped in C, and both are fixed the same three ways.
Precedence is the answer to "which operator gets to be the parent". `1 + 2 * 3` builds as `+(1, *(2, 3))`, and every mechanism for arranging that — grammar layers, declaration tables, binding powers — is producing the same tree by a different route.
Precedence handles two different operators; associativity handles two of the same. `a - b - c` is `(a - b) - c` in every language you use, and `2 ** 3 ** 2` is 512 in Python and 64 in MATLAB — the same operator, associating opposite ways.
The rule that makes `-` group correctly is the same rule that makes a recursive-descent parser call itself forever. LR parsers prefer it, top-down parsers cannot survive it, and the standard fix trades a grammar rewrite for a loop that folds left by hand.