Your question is interesting in several ways, as it requires careful
distinctions for several issues. But your vision seems to me to be
essentially correct. I did not read your reference before writing most
of this answer to avoid biasing my answer.
First, your statement Variables are symbolic names for memory
addresses
, it is almost correct, but confuses the concept and its
usual implementation. A variable is actually just a container that can
contain a value that can be changed. Usually, this container is
implemented on a computer as a bock of memory space, characterized by
and address and a size since variables may contain object that
require representations with more or less information.
But I will consider mostly a more abstract point of view of the
semantics of languages, independently of implementation techniques.
So variables are just containers from an abstract point of view. Such
a container need not have a name. However, languages often have
variables that are named by associating to it an identifier, so that
uses of the variable can be expressed by the identifier. A variable
can actually have several identifiers through various aliasing
mechanism. A variable can also be a subpart of a larger variable: an
example is a cell of an array variable, which can be named by
specifying the array variable and the index of the cell, but could as
well be also associated with identifiers through aliasing.
I am deliberately using the word container that is somewhat neutral, to avoid invoking other words that may be semantically loaded technically. It is actually close to the concept of reference described in wilipedia, which is often confused with a memory address. The word pointer itself is often understood as a memory address, but I do not think that is meaningful when considering most high-level languages, and probably inappropriate in the discussion paper you refer to (though addresses can be used), as it is inappropriately referring to a specific implementation. However, it is appropriate for a language like C, which is supposed to be much closer to
implementation concepts and the machine architecture.
Actually, if you look at variables or values at the implementation
level, there may be several complex systems of indirection, of
"machine level pointers", but that are (and should be) invisible to
the user, so that the abstract point of view I develop can be valid.
For most programming languages, the user should not have to worry, or
even know, about implementation, as implementation can vary a lot for a given
language. This may not be true for some languages, such as C, that are
intentionally close to the machine architecture, as an advanced
substitute for assembly languages that are in almost direct relation
to explicit binary coding, but far too low level for convenient use in most situations.
What the user of a language should know, and sometimes it should be even less than
that, is what are values and associated operations, where they can be
contained, how they can be associated to names, how the naming system
works, how can new kinds of values be defined, etc.
So another important concept is identifiers and naming. Naming an
entity (a value) can be done by associating an identifier with a value
(usually in a declaration). But a value can also be obtained by
applying operations to other named values. Names can be reused, and
there are rules (scoping rules) to determine what is associated to a
given identifier, according to context of use. There are also special
names, called litterals, to name the values of some domains, such as
integers (e.g. $612$) or boolean (e.g. true).
The association of an unchanging value with an identifier is usually
called a constant. Litterals are constants in that sense.
"Value containers" can also be considered as values, and their
association with an identifier is a variable in the usual "naive"
sense that you have been using. So you might say that a variable is a
"container constant".
Now you might wonder what is the difference between associating an
identifier with a value (constant declaration) or assigning a value to
a variable, i.e. storing the value in the container defined as a
container constant. Essentially, declaration may be seen as an
operation that defines a notation, that associate an identifier which
is a syntactic entity to some value which is a semantic entity.
Assignment is a purely semantics operation that modifies a state,
i.e. modifies the value of a container. In some sense, declaration is
a meta concept with no semantic effect, other than providing a naming
(i.e. syntactic) mechanism for semantics entities.
Actually, assignments are semantic operations that occur dynamically
as the program is executed, while declarations have a more syntactic
nature and are usually to be interpreted in the text of the program,
independently of execution. This is why static scoping (i.e. textual
scoping) is usually the natural way to understand the meaning of
identifiers.
After all this, I can say that a pointer value is just another name for a container,and a pointer variable is a
container variable, i.e. a container (constant) that can contain another
container (with possible limitations on the containing game imposed by
some type system).
Regarding code, you state [pointers] might indicate the entry point
to a section of code and can be used to call that code
. Actually this
is not quite true. A section of code is often meaningless alone
(from high level or implementation point of view). From a high-level
point of view, code usually contains identifiers, and you have to
interpret these identifiers in the static context where they were
declared. But there is actually a possible duplication of the same
static context, due essentially to recursion which is a dynamic
(run-time) phenomenon, and the code can only be executed in an
appropriate dynamic instance of the static context. This is a bit
complex, but the consequence is that the proper concept is that of a
closure that associate a piece of code and an environment where the
identifiers are to be interpreted. The closure is the proper semantic
concept, i.e. is a properly definable semantic value. Then you can
have closure constants, closure variables, and pointers to closures,
which are containers that can contain another container containing a
closure.
A function is a closure, usually with some parameters to define or
initialise some of its entities (constants and variables).
I am skipping many variations on the uses of these mechanisms.
Closures can be used to define OO structures in imperative or
functional languages. Actually, early work on OO style (probably
before the name) was done that way.
The paper you reference, which I skimmed quickly, seems to be an
interesting one, written by a competent person, but possibly not an
easy reading if you do not have significant experience with a variety
of languages and their underlying computational models.
But remember: many things are in the eyes of the beholder, as long as
he preserves a consistent view. Points of view may differ.
Does this answer your question?
PS: This is a long answer. If you consider some part of it inadequate, please be explicit about which it is. Thank you.