With machine languages, generally there are no names, limited scoping, and binding is not really a relevant concept.
All assemblers allow some sort of names; the most minimal ones supported are generally called labels and definitions, but fancier assemblers can have other types of names such as macros.
Since assembly languages actually provide the greatest freedom (all of the machine's resources are there for the programmer in their fullest extent), what is the rationale for "higher level" languages?
Obviously, you get more (if not perfect) machine independence. No longer do you care about the most that you can do with the hardware; it becomes instead using the greatest common hardware efficiently (think gcd() rather than max()).
In assembly, even with heavy use of macros, porting code from one architecture to a reasonably differing one requires more work than any high level language.
More imporatantly, higher level languages are generally good at something; specialized languages, like gp/pari, are even "superb" rather than "generally good".
While you lose a certain amount of freedom, you (should) gain a lot of expressivity, the ability to pithily and clearly express ideas.
For instance, look at the expressivity of Haskell for the "hello_world" program of the functional world, the factorial function.
Your text gives this definition on pages 111-112:
"A name is a mnemonic character string used to represent something else. Names in the most languages are identifiers (alphanumeric tokens), though certain other symbols, such as + or :=, can also be names. Names allow us to refer to variables, constants, operations, types, and so on using symbolic identifiers rather than low-level concepts like addresses."
A "binding" is an association between a name and what it represents.
"Binding time" is the time when we decide on an association.
Arguments and return values: One of my favorite sentences from the text is on page 116: "Modern compilers keep these in registers whenever possible, but sometimes space in memory is needed." Now, if we could get more operating systems to use the same regimen for system calls! (Linux, to its credit, does do so; the BSDs, as illustrated above, don't.)
Temporaries: (obviously) use registers whenever possible.
Nested scoping rules: in languages which allow nested routines, it is very common for a variable name from a parent routine to be available to a child routine.
How does a child does this? With stack-based languages, generally a child activation keeps a pointer to its parent activation (not necessarily the same lexical parent/child relationship, though, which could be grandparent/child relationship, for instance.)
How do you have mutual recursion, where A calls B calls A? One has to be defined before the other, and thus there is a dilemma.
You could take the C route, of having "declarations" and "definitions" be different things; then you could declare both A and B, and then both function definitions would be aware of the other.
Modules into which names must be explicitly imported are "closed scopes."
Modules that do not not require imports are "open scopes".
"Selectively open" allows the programmer to add a qualifier; for instance, if A exports buzz, then B can automatically reference it as A.buzz; it becomes visible if B explicitly imports the name.
Some languages treat modules as a mediator, managing objects with various means to express the semantics destroy/create/change
Some languages treat modules as defining "types", rather than a mere mechanism for encapsulation.
When the bindings between names and objects depend on the flow of control at run time rather than just lexical scope, you have "dynamic scoping".
TeX, for instance, uses dynamic scoping, as does Forth. Perl allows for both, as noted in footnote 10 at the bottom of page 140.
To keep track of names in a statically scoped language, the compiler for that language merely keeps a symbol table, mapping a name to the information known about the symbol.
To track names in a dynamically scoped language, the run-time for that language must keep up with the mapping between names and objects.
Aliases (yipes!?): aliasing (i.e., two different names in a scope that refer to the same object) makes it harder to understand, much less optimize, programs.
Overloading: the trick with overloading of operator and function names is usually being able to distinguish the versions by the types of the arguments.
First class value: it can be passed as a paramter, returned from a subroutine, or assigned into a variable.
Second class value: it can be passed as a paramter. It cannot be returned from a subroutine or assigned into a variable.
Third class value: it cannot be passed as a parameter, returned from a subroutine, or assigned into a variable.
Typically, integers, e.g., are first class values, and labels are third class values.
Subroutines in functional langauges are first class; usually first class in most scripting languages, and often second class in most other languages.
#define emit(a) printf("%d",a)
emit(3); ==> printf("%d",3);