The Method Browser
Rules and Actions
Symbol Table
Appendix B summarized the different versions of the stack machine. This appendix contains tables which index the stack machine compilers for the little language developed in chapters six, seven, and eight. The table entries are linked to the examples, to the documentation, and from there to the sources.
These compilers generate code during recognition, i.e., in the action methods.
The action classes extend from example 6/10
(Arithmetic10)
to example 6/11 (Control11),
7/4 (Functions04),
7/6 (Parameters06),
and 7/9 (Blocks09).
To implement nested functions
example 7/13 defines the mix-in Nest13
to extend Blocks09
and support function definitions at greater depth — which requires a static link.
To implement global first-order functions
example 8/1 defines the mix-in Global01
to extend Blocks09
and primarily support type checking with function types
for variables, functions, parameters, and argument values.
To implement nested functions as argument values
example 8/8 defines the mix-in Pass08
to extend Blocks09 and Nest13;
the language forbids using functions and results or variables with function values.
Finally, to implement nested first-order functions,
example 8/14 defines the mix-in First14
to extend the implementation in example 8/1
and support dynamic memory management for frames.
The Method Browser
The method browser can be used to study the evolution of the action classes and methods and, in particular, to see where a method is first defined.
By default it will load the sources of the implementation of the little language
in chapters six through eight, but file parameters can be used in a search string
to load JavaScript files from the modules directory.
Patterns are used to extract module, class or mix-in, and method names, and the source text of the methods. The patterns assume a particular coding style, mostly based on white space and nesting.
The names are displayed in a table with columns for modules, classes or mix-ins, methods, and nested methods. Names can be selected by clicking in each column. Multiple selections within a column are considered alternatives, selections across columns must all be satisfied. A column without selections is a wildcard.
Selected names have a darker blue background, names that could be added to a selection have a lighter blue background.
Each column can be scrolled vertically. If the mouse hovers over a column (indicated by a focus border) a keypress will scroll to names with the corresponding initial and the delete key will clear all selections in the column.
A combination of names selects methods which can be displayed, sorted alphabetically by method name, or by class or mix-in. A single method is displayed as soon as it is selected.
An initial selection can be defined by specifying one or more module,
item, method, and op parameters in a search string for the page.
A show parameter requests immediate display of the selection.
op refers to nested methods, i.e., methods within classes
which are nested into top-level classes, e.g., the classes
which are used to represent types, variables, and functions
in the implementation of the little language.
The nested methods are also located by patterns based on coding style.
Grammar Rules and Actions
This table shows how the grammar rules and actions are defined or overridden. Numbers reference the example where a rule was used and ⊕ references action method definitions or overrides.
| rules |
|||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
list: stmt [{ ';' stmt }]; |
6/10 | ||||||||||||||||
prog: stmts; |
6/11 | ⊕ | |||||||||||||||
prog: [ vars ] funs; |
7/4 | ⊕ | 7/6 | 7/9 | 7/13 | ||||||||||||
prog: [ typedcls ] [ vars ] funs; |
8/1 | ⊕ | 8/8 | 8/14 | |||||||||||||
typedcls: { 'type' typedcl [{ ',' typedcl }] ';' }; |
8/1 | ⊕ | 8/8 | 8/14 | |||||||||||||
typedcl: Name '(' [ types ] ')' [ ':' typename ]; |
8/1 | ⊕ | 8/14 | ||||||||||||||
typedcl: Name '(' [ types ] ')' [ ':' number' ]; |
8/1 | ⊕ | 8/8 | ||||||||||||||
types: typename [{ ',' typename }]; |
8/1 | ⊕ | 8/8 | 8/14 | |||||||||||||
typename: Name | 'number'; |
8/1 | ⊕ | 8/8 | 8/14 | |||||||||||||
vars: 'var' names ';'; |
7/4 | 7/6 | 7/9 | 7/13 | |||||||||||||
vars: 'var' varname [{ ',' varname }] ';'; |
8/1 | 8/8 | 8/14 | ||||||||||||||
varname: Name [ ':' type ]; |
8/1 | ⊕ | 8/14 | ⊕ | |||||||||||||
varname: Name; |
8/8 | ||||||||||||||||
type: Name | 'number'; |
8/1 | ⊕ | 8/14 | ||||||||||||||
names: Name [{ ',' Name }]; |
7/4 | ⊕ | 7/6 | 7/9 | 7/13 | 8/1 | 8/8 | 8/14 | |||||||||
funs: { fun }; |
7/4 | 7/6 | 7/9 | 7/13 | 8/1 | 8/8 | 8/14 | ||||||||||
fun: head [ 'begin' stmts 'end' ] ';'; |
7/4 | ⊕ | |||||||||||||||
fun: head parms [ block ] ';'; |
7/6 | ⊕ | 7/9 | 7/13 | 8/1 | 8/8 | 8/14 | ||||||||||
head: 'function' Name; |
7/4 | ⊕ | 7/6 | 7/9 | 7/13 | ⊕ | 8/1 | 8/8 | 8/14 | ||||||||
parms: '(' [ names ] ')'; |
7/6 | ⊕ | 7/9 | 7/13 | |||||||||||||
parms: '(' [ names ] ')' [ ':' Name ]; |
8/1 | ⊕ | 8/8 | 8/14 | |||||||||||||
block: 'begin' [ vars ] stmts 'end'; |
7/6 | ||||||||||||||||
block: begin [ vars ] stmts 'end'; |
7/9 | ⊕ | 8/1 | ||||||||||||||
block: begin body 'end'; |
7/13 | ⊕ | 8/8 | 8/14 | |||||||||||||
begin: 'begin'; |
7/9 | ⊕ | 7/13 | 8/1 | 8/8 | 8/14 | |||||||||||
body: [ vars ] [ funs ] stmts; |
7/13 | ||||||||||||||||
stmts: stmt [{ ';' stmt }]; |
6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | 8/8 | 8/14 | |||||||||
stmt: sum; |
6/10 | ⊕ | |||||||||||||||
stmt: assign | print | loop | select; |
6/11 | ⊕ | |||||||||||||||
stmt: assign | print | return | loop | select; |
7/4 | 7/6 | |||||||||||||||
stmt: assign | print | return | block | loop | select; |
7/9 | 7/13 | 8/1 | 8/8 | 8/14 | ||||||||||||
assign: Name '=' sum; |
6/11 | ⊕ | |||||||||||||||
assign: Name [ '=' sum ]; |
7/4 | ⊕ | |||||||||||||||
assign: symbol action; |
7/6 | ⊕ | 7/9 | 7/13 | 8/1 | 8/8 | 8/14 | ||||||||||
action: store | call; |
7/6 | 7/9 | 7/13 | 8/1 | 8/8 | 8/14 | |||||||||||
store: '=' sum; |
7/6 | ⊕ | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ⊕ | ||||||||
call: args; |
7/6 | 7/9 | 7/13 | 8/8 | |||||||||||||
call: { args }; |
8/1 | 8/14 | ⊕ | ||||||||||||||
args: '(' [ sums ] ')'; |
7/6 | ⊕ | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||||
print: 'print' sums; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
sums: sum [{ ',' sum }]; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
return: 'return' [ sum ]; |
7/4 | ⊕ | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ⊕ | |||||||
loop: While cmp Do stmts 'od'; |
6/11 | ⊕ | 7/4 | 7/6 | |||||||||||||
loop: While cmp Do [ vars ] stmts 'od'; |
7/9 | ⊕ | 8/1 | ||||||||||||||
loop: While cmp Do body 'od'; |
7/13 | ⊕ | 8/8 | 8/14 | |||||||||||||
While: 'while'; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | 8/8 | 8/14 | ||||||||
Do: 'do'; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | ⊕ | 7/13 | 8/1 | 8/8 | 8/14 | |||||||
select: 'if' cmp Then stmts [ Else stmts ] 'fi'; |
6/11 | ⊕ | 7/4 | 7/6 | |||||||||||||
select: 'if' cmp then [ else ] 'fi'; |
7/9 | ⊕ | 7/13 | 8/1 | 8/8 | 8/14 | |||||||||||
then: Then [ [ vars ] stmts ]; |
7/9 | ⊕ | 8/1 | ||||||||||||||
then: Then [ body ]; |
7/13 | 8/8 | 8/14 | ||||||||||||||
else: Else [ vars ] stmts ; |
7/9 | ⊕ | 8/1 | ||||||||||||||
else: Else body ; |
7/13 | ⊕ | 8/8 | 8/14 | |||||||||||||
Then: 'then'; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | ⊕ | 7/13 | 8/1 | 8/8 | 8/14 | |||||||
Else: 'else'; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | ⊕ | 7/13 | 8/1 | 8/8 | 8/14 | |||||||
cmp: sum rel; |
6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ||||||||
rel: eq | ne | gt | ge | lt | le; |
6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | 8/8 | 8/14 | |||||||||
eq: '=' sum; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
ne: '<>' sum; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
gt: '>' sum; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
ge: '>=' sum; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
lt: '<' sum; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
le: '<=' sum; |
6/11 | ⊕ | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
sum: 'let' Name '=' sum | product [{ add | subtract }]; |
6/10 | ⊕ | |||||||||||||||
sum: product [{ add | subtract }]; |
6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ||||||||
add: '+' product; |
6/10 | ⊕ | 6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ||||||
subtract: '-' product; |
6/10 | ⊕ | 6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ||||||
product: signed [{ multiply | divide }]; |
6/10 | 6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
multiply: '*' signed; |
6/10 | ⊕ | 6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ||||||
divide: '/' signed; |
6/10 | ⊕ | 6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ||||||
signed: [ '-' ] term; |
6/10 | ⊕ | 6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ||||||
term: input | number | name | '(' sum ')'; |
6/10 | 6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | |||||||
input: 'input' [ Number ]; |
6/10 | ⊕ | 6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ||||||
number: Number; |
6/10 | ⊕ | 6/11 | 7/4 | 7/6 | 7/9 | 7/13 | 8/1 | ⊕ | 8/8 | 8/14 | ||||||
name: Name; |
6/10 | ⊕ | 6/11 | 7/4 | ⊕ | ||||||||||||
name: symbol [ args ]; |
7/6 | ⊕ | 7/9 | 7/13 | 8/8 | ||||||||||||
name: symbol [{ args }]; |
8/1 | ⊕ | 8/14 | ||||||||||||||
symbol: Name; |
7/6 | ⊕ | 7/9 | 7/13 | 8/1 | 8/8 | 8/14 |
Symbol Table Entries
Symbol table entries have a common base class Symbol
which ensures that every symbol has a name
and can reference the owner, i.e., the action class which defines the symbol's class;
therefore,
the symbol classes are inner classes of an action class as the owner.
Getters in the action classes are used to access the symbol classes because getters can be overwritten in subclasses to silently return extended symbol classes. It should be noted, however, that a reference to a getter can be confused with a reference to a method with the same name, i.e., given the class definition
class X {
get x () { /* ... */ }
x () { /* ... */ }
}
the reference (new X()).x is ambiguous;
e.g.,
the Node.js JavaScript compiler will return the method function
and not note an error.
| property | Symbol |
usage | ||||||
|---|---|---|---|---|---|---|---|---|
.owner |
7/4 | outer class' object | ||||||
.name |
7/4 | symbol's name |
Variables
Variable descriptions have a common base class Var
which is extended by the various action classes.
The table links the properties of the descriptions
to the classes and examples where they are defined or overridden.
() indicates a method.
+ indicates that an override references super.
| property | Var |
Var |
Var |
Var |
Var |
Var |
usage | |
|---|---|---|---|---|---|---|---|---|
.addr |
7/4 | memory address or offset | ||||||
.depth |
7/6 | 7/13 | (static) level | |||||
.type |
8/1 | variable's type | ||||||
.load() |
7/4 | 7/6 | 7/13 | 8/8 | 8/14 | generates Load* |
||
.storeOk() |
7/4 | 8/1 | +8/8 | true unless store() is in error |
||||
.store() |
7/4 | 7/6 | 7/13 | 8/14 | generates Store* |
|||
.call() |
8/1 | generates Call* |
||||||
.toString() |
7/4 | 7/6 | 7/13 | +8/1 | text representation |
Functions
Function descriptions have a common base class Fun
which is extended by the various action classes.
The table links the properties of the descriptions
to the classes and examples where they are defined or overridden.
[] indicates that a property is a list.
() indicates a method.
+ indicates that an override references super.
| property | Fun |
Fun |
Fun |
Fun |
Fun |
Fun |
Fun |
usage |
|---|---|---|---|---|---|---|---|---|
.start |
7/4 | false or code address |
||||||
.calls[] |
7/4 | slots for Call* |
||||||
.returns[] |
7/4 | slots for Branch exit |
||||||
.parms |
7/6 | number of parameters | ||||||
.addr |
7/6 | result value offset | ||||||
.locals get/set |
7/6 | 7/9 | maps local names to descriptions | |||||
.size get/set |
7/6 | 7/9 | next address in frame | |||||
.blocks[] |
7/9 | .locals/.size stack |
||||||
.frameSize |
7/9 | frame size | ||||||
.depth |
7/13 | (static) level | ||||||
.scope |
7/13 | block containing definition | ||||||
.type |
8/1 | function's type | ||||||
.loads[] |
8/1 | slots for Push* |
||||||
.entry() |
7/4 | 7/6 | +7/13 | sets start, reserves Entry |
||||
.undo() |
7/4 | +7/6 | undoes entry() |
|||||
.setParms() |
7/6 | +7/13 | 8/1 | 8/8 | 8/14 | sets .parms .addr, types |
||
.call() |
7/4 | +8/8 | +8/14 | generates Call* |
||||
.return() |
7/4 | generates Branch exit |
||||||
.storeOk() |
7/4 | 7/13 | +8/1 | true unless store() is in error |
||||
.store() |
7/4 | 7/6 | 7/13 | 8/14 | generates Store* result, types |
|||
.load() |
8/1 | +8/8 | +8/14 | generates Push* |
||||
.push() |
7/9 | pushes .blocks[] |
||||||
.pop() |
7/9 | +7/13 | pops .blocks[], sets frame size |
|||||
.end() |
7/4 | +7/9 | +8/1 | fixes forward references, exit() |
||||
.exit() |
7/4 | 7/6 | 7/9 | 7/13 | 8/8 | 8/14 | generates Entry, Exit, Return |
|
.toString() |
7/4 | 7/6 | 7/9 | +7/13 | +8/1 | text representation |
Blocks
A Block represents a scope of names
to support block structure.
| property | Block |
usage | |
|---|---|---|---|
.locals |
7/9 | maps names in scope to descriptions | |
.size |
7/9 | next address in scope | |
.toString() |
7/9 | text representation | |
.bypass |
7/13 | address of branch bypassing functions |
Types
There is just one type description class Type
and there is a separate, global symbol table typeSymbols
for types to allow matching of functions and types on their names.
Two type values have reserved names: number describes number values
and,
for convenience,
main describes a function without arguments which returns a number.
| property | Type |
usage |
|---|---|---|
.parms[] |
8/1 | null or list of parameter types |
.returns |
8/1 | null or result type |
.isFun |
8/1 | true if function type |
.toString() |
8/1 | text representation |