The scope of an identifier in a program is those parts of the program where the identifier refers to (or, is bound to) some particular thing. There are two primary types of scope in programming languages, lexical scope (a.k.a. static scope) and dynamic scope.
Lexical scope is the name for the situation in which the scope matches some static,
identifiable part of the text of the source code. For example, in C, the lexical scope
is usually between the '{' symbol just before the declaration if the identifier and the
corresponding '}' symbol (except in sub-blocks in which the same identifier is
redeclared). One can tell by examining the text whether a particular part of the code is
within a particular lexical scope or not. In short, identifiers are linked with what they
identify at compile-time. The proces of binding lexical-scope identifiers to objects is called lexical binding.
Dynamic scope is a different beast, old implementations of Lisp implement this dynamic (ariels tells me that newer implementations of Lisp all have lexical binding by default). In this case, identifiers are linked with what they identify at run-time; the
scope begins when the identifier is declared and ends usually at the end of the smallest
enclosing block. A function (A) in (old) Lisp, for example, may reference an
identifier (x) which is not declared in that function. In that case, the value
of the identifier is taken from the context from which the function was called - for
example, if function B declares x and then calls A, the
identifier x within that call to A will reference the x
from B. Another function C may also declare a different
x, and call A, in which case x within that call to
A will reference the x from C. A programmer taking
advantage of dynamic scope for some function or procedure should not only document
parameters and return values, but also all the other relavent elements of the context
from which it is called. The proces of binding dynamic-scope identifiers to objects is called dynamic binding
Dynamic scope can be implemented as a stack of (identifier, value) pairs, such that
an entry is pushed onto the stack whenever an identifier is declared, popped off when
the identifier reaches the end of it's scope, and whenever an identifier is referenced the
stack is searched from the top down to find it's value.
An example will help make the concept clear; consider the following pseudo-code:
1 : define A
2 : {
3 : declare x as integer
4 : define A.A
5 : {
6 : ...
7 : output x
8 : ...
9 : }
10 : define A.B
11 : {
12 : declare x as string
13 : ...
14 : }
15 : ...
16 : call A.A
17 : call A.B
18 : ...
19 : }
20 : define B
21 : {
22 : declare x as real
23 : ...
24 : call A.A
25 : ...
26 : }
The lexical scope of the x declared in line 3 is lines 3 to 18,
excluding lines 12 to 13. The lexical scope of the x declared in line
12 is lines 12 to 13. The lexical scope of the x declared in line 22 is lines 22
to 25. If there were no 'call's, the dynamic scopes would be effectively the
same. Lines 7, 16, and 24 illustrate the difference between the two types of scope. For
lexical scoping, at compile-time, the x referenced in line 7 is associated with
the static context of x declared in line 3 - therefore, line 7 will
always output an integer. For dynamic scoping, at run-time, when executing
line 16, the run-time context associates x with an integer, so line 7 will output
an integer; but, when executing line 24, the run-time context associates x with a
real, so line 7 will output a real. Therefore, with dynamic scoping, line 7 will
not always output an integer - in fact, if it weren't for line 16, it may
never output an integer.