20 Commits (7134b09e502ca2ff17b165e72b04e88f7973fbab)

Author SHA1 Message Date
David Majda 7134b09e50 Merge |allocateRegisters| and |computeParams| passes
The purpose of this change is to avoid the need to index register
variables storing match results of sequences whose elements are labeled.
The indexing happened when match results of labeled elements were passed
to action/predicate functions.

In order to avoid indexing, the register allocator needs to ensure that
registers storing match results of any labeled sequence elements are
still "alive" after finishing parsing of the sequence. They should not
be used to store anything else at least until code of all actions and
predicates that can see the labels is executed. This requires that the
|allocateRegisters| pass has the knowledge of scoping. Because that
knowledge was already implicitly embedded in the |coputeParams| pass,
the logical step to prevent duplication was to merge it with the
|allocateRegisters| pass. This is what this commit does.

As a part of the merge the tests of both passes were largely refactored.
This is both to accomodate the merge and to make the tests in sync with
the code again (the tests became a bit out-of-sync during the last few
commits -- they tested more than was needed).

The speed/size impact is slightly positive:

Speed impact
------------
Before:     849.86 kB/s
After:      858.16 kB/s
Difference: 0.97%

Size impact
-----------
Before:     876618 b
After:      875602 b
Difference: -0.12%

(Measured by /tools/impact with Node.js v0.6.18 on x86_64 GNU/Linux.)
12 years ago
David Majda 2d36ebeb59 Mental model change: Variables do not form a stack, they are registers
This commit changes the model underlying parser variables used to store
match results and parse positions. Until now they were treated as a
stack, now they are thought of as registers. The actual behavior does
not change (yet), only the terminology.

More specifically, this commit:

  * Changes parser variable names from |result0|, |result1|, etc. to
    |r0|, |r1|, etc.

  * Changes various internal names and comments to match the new model.

  * Renames the |computeVarIndices| pass to |allocateRegisters|.
12 years ago
David Majda 2c8b323ade Replace variable name computations by computations of indices
This commit replaces all variable name computations in |computeVarNames|
and |computeParams| passes by computations of indices. The actual names
are computed later in the |generateCode| pass.

This change makes the code generator the only place that deals with the
actual variable names, making them easier to change for example.

The code generator code seems bit more complicated after the change, but
this complexity will pay off (and mostly disappear) later.
12 years ago
David Majda 4f86fca3d7 Make the code emitter a compiler pass
This gives the compiler a more regular structure.
12 years ago
David Majda 44852fa6b4 Pass |options| to compiler passes 12 years ago
David Majda f046e0a838 Move compiler-related source files and tests into a subdirectory 12 years ago
David Majda 9615eb4bb6 Allow passing options to |PEG.buildParser|
These get passed down to the emitter templates.
12 years ago
David Majda 4cf50bcf9f Move param computations from the emitter into a separate pass
This has two main benefits:

  1. The knowledge about scoping params in at one designated place,
     making all future adjustments in this area easier.

  2. Action-related code does not handle sequences specially anymore.
     Such knowledge/behavior doesn't belong there.
12 years ago
David Majda efc38eef9b Consolidate all variable name computations into one compiler pass
Before this change, knowledge about variable names was spread between
the |computeStackDepths| pass and the code emitter code. For example,
the fact that the |&...| expression needs one variable to store a
position was represented in both places.

This changes consolidates that knowledge and introduces a new
|computeVarNames| pass. This pass replaces old |computeStackDepths|
pass, does all computations realted to variable names and stores the
results in the AST. Note that some knowledge about variables
(inevitably) remained in emitter code templates.

Beside DRYing things up, this change simplifies the emitter
significantly. By storing variable names in the AST it also allows
introduction of a pass that will identify parameters passed to actions
using proper symbol tables. Right now, this is done in a hackish way
directly in the emitter, which won't work well with changes planned in
GH-69.
12 years ago
David Majda a19ea83ffa Replace |for| loop iterating over compiler passes with |each| 13 years ago
David Majda cd5490dee4 Make pass list customizable via |PEG.compiler.appliedPassNames| property 13 years ago
David Majda 8a0276ffb7 Unify checks and passes
There is no real reason to have them separated.
13 years ago
David Majda 6cd5bdc5e6 Passes now do not return anything (they always modify the AST in-place) 13 years ago
David Majda 3983f46d5d Rename |reportMissingReferencedRules| check to |reportMissingRules|
The new name is shorter, there is no real loss of meaning.
13 years ago
David Majda 64d26e5db2 Make names of compiler checks and passes verbs 13 years ago
David Majda cc4910d9b9 src/compiler.js: Fix variable redefinition
Fixes the following JSHint error:

  ./src/compiler.js: line 23, col 16, 'i' is already defined.
13 years ago
David Majda d123cf0eda Rewrite variable handling in generated parsers
Before this commit, variables for saving match results and parse
positions in generated parsers were not used efficiently. Each rule
basically used its own variable(s) for storing the data, with names
generated sequentially during code emitting. There was no reuse of
variables and a lot of unnecessary assignments between them.

It is easy to see that both match results and parse positions can
actually be stored on a stack that grows as the parser walks deeper in
the grammar tree and shrinks as it returns. Moreover, if one creates a
new stack for each rule the parser enters, its maximum depth can be
computed statically from the grammar. This allows us to implement the
stack not as an array, but as a set of numbered variables in each
function that handles parsing of a grammar rule, avoiding potentially
slow array accesses.

This commit implements the idea from the previous paragraph, using
separate stack for match results and for parse positions. As a result,
defined variables are reused and unnecessary copying avoided.

Speed implications
------------------

This change speeds up the benchmark suite execution by 2.14%.

Detailed results (benchmark suite totals as reported by "jake benchmark"
on Node.js 0.4.8):

-----------------------------------
 Test #      Before        After
-----------------------------------
      1   129.01 kB/s   131.98 kB/s
      2   129.39 kB/s   130.13 kB/s
      3   128.63 kB/s   132.57 kB/s
      4   127.53 kB/s   129.82 kB/s
      5   127.98 kB/s   131.80 kB/s
-----------------------------------
Average   128.51 kB/s   131.26 kB/s
-----------------------------------

Size implications
-----------------

This change makes a sample of generated parsers 8.60% smaller:

Before:

  $ wc -c src/parser.js examples/*.js
   110867 src/parser.js
    13886 examples/arithmetics.js
   450125 examples/css.js
   632390 examples/javascript.js
    61365 examples/json.js
  1268633 total

After:

  $ wc -c src/parser.js examples/*.js
    99597 src/parser.js
    13077 examples/arithmetics.js
   399893 examples/css.js
   592044 examples/javascript.js
    54797 examples/json.js
  1159408 total
13 years ago
David Majda a42b957573 Remove now mostly useless comment headers from the code 14 years ago
David Majda f82a4ebf28 Compiler checks and passes are named for easier reference from tests 14 years ago
David Majda e59f3ba338 Split the source code into several files, introduce build system
The source code is now in the src directory. The library needs to be
built using "rake", which creates the lib/peg.js file by combining the
source files.
14 years ago