Skip to content

Commit 507fe8b

Browse files
committed
Forked jakubledl\dissect
0 parents  commit 507fe8b

File tree

87 files changed

+6712
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+6712
-0
lines changed

.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
vendor/
2+
composer.phar
3+
composer.lock

.idea/dissect.iml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/misc.xml

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.idea/modules.xml

+8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

.travis.yml

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
language: php
2+
3+
php:
4+
- 5.3
5+
- 5.4
6+
7+
branches:
8+
only:
9+
- master
10+
- develop
11+
12+
before_script:
13+
- wget http://getcomposer.org/composer.phar
14+
- php composer.phar dump-autoload

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
Changelog
2+
=========
3+
4+
1.0.1 (2013-01-29)
5+
------------------
6+
7+
- 2b40f94: Fixed an invalid format in the CLI
8+
9+
1.0.0 (2013-01-15)
10+
------------------
11+
12+
- First release.

README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Welcome to Dissect!
2+
- [master](https://github.com/jakubledl/dissect/tree/master) [![build status](https://travis-ci.org/jakubledl/dissect.png?branch=master)](https://travis-ci.org/jakubledl/dissect) - this branch always contains the last stable version.
3+
- [develop](https://github.com/jakubledl/dissect) [![build status](https://travis-ci.org/jakubledl/dissect.png?branch=develop)](https://travis-ci.org/jakubledl/dissect) - the unstable development branch.
4+
5+
Dissect is a set of tools for lexical and syntactical analysis written
6+
in pure PHP.
7+
8+
Documentation?
9+
--------------
10+
11+
[Here][docs].
12+
13+
[docs]: https://github.com/jakubledl/dissect/blob/master/docs/index.md

TODO.md

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
Goals
2+
=====
3+
4+
1.1
5+
---
6+
7+
- Optional operator precedence support (à la *yacc*, *bison*) - ✔
8+
- A performance-oriented regex lexer (based on doctrine/lexer) - ✔
9+
- An option to generate a hybrid recursive ascent parser - □
10+
11+
1.0
12+
---
13+
14+
- Compute reduction lookahead by the channel algorithm from *yacc*
15+
instead of the current LALR-by-SLR algorithm - ✔
16+
- Change the analyzer API to allow for grammar debugging
17+
(provide access to resolved conflicts, dumping the automaton to DOT ...) - ✔
18+
- Provide classes for dumping the parse table to PHP (both the dev & prod version) - ✔

UNLICENSE

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
This is free and unencumbered software released into the public domain.
2+
3+
Anyone is free to copy, modify, publish, use, compile, sell, or
4+
distribute this software, either in source code form or as a compiled
5+
binary, for any purpose, commercial or non-commercial, and by any
6+
means.
7+
8+
In jurisdictions that recognize copyright laws, the author
9+
of this software dedicates any and all copyright interest in the
10+
software to the public domain. I make this dedication for the benefit
11+
of the public at large and to the detriment of our heirs and
12+
successors. I intend this dedication to be an overt act of
13+
relinquishment in perpetuity of all present and future rights to this
14+
software under copyright law.
15+
16+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19+
IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
20+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22+
OTHER DEALINGS IN THE SOFTWARE.
23+
24+
For more information, please refer to <http://unlicense.org/>

bin/dissect

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
#!/usr/bin/env php
2+
<?php
3+
4+
require __DIR__ . '/dissect.php';

bin/dissect.php

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
define('DISSECT_VERSION', 'DEV');
4+
5+
if (is_dir($vendor = getcwd() . '/vendor')) {
6+
require $vendor . '/autoload.php';
7+
}
8+
9+
if (is_dir($vendor = __DIR__ . '/../vendor')) {
10+
require $vendor . '/autoload.php';
11+
} elseif (is_dir($vendor = __DIR__ . '/../../../../vendor')) {
12+
require $vendor . '/autoload.php';
13+
} else {
14+
die(
15+
'You must set up the project dependencies.' . PHP_EOL .
16+
'To do that, run the following commands:' . PHP_EOL . PHP_EOL .
17+
'$ curl -s http://getcomposer.org/installer | php' . PHP_EOL .
18+
'$ php composer.phar install' . PHP_EOL
19+
);
20+
}
21+
22+
if (!class_exists('Symfony\Component\Console\Application')) {
23+
die(
24+
'You must install the symfony/console package in order ' .
25+
'to use the command-line tool.' . PHP_EOL
26+
);
27+
}
28+
29+
$app = new Dissect\Console\Application(DISSECT_VERSION);
30+
$app->run();

composer.json

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
{
2+
"name": "jakubledl/dissect",
3+
"description": "Lexing and parsing in pure PHP",
4+
"keywords": ["lexing", "parsing", "ast", "parser"],
5+
"homepage": "https://github.com/jakubledl/dissect",
6+
"license": "unlicense",
7+
"authors": [
8+
{
9+
"name": "Jakub Lédl",
10+
"email": "[email protected]"
11+
}
12+
],
13+
14+
"require": {
15+
"php": ">=5.3.3"
16+
},
17+
18+
"require-dev": {
19+
"symfony/console": "~2.1"
20+
},
21+
22+
"suggest": {
23+
"symfony/console": "for the command-line tool"
24+
},
25+
26+
"bin": ["bin/dissect.php", "bin/dissect"],
27+
28+
"autoload": {
29+
"psr-0": { "Dissect": ["src/"] }
30+
}
31+
}

docs/ast.md

+141
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
Building an AST
2+
===============
3+
4+
Often, when parsing a language that's more complex than
5+
[mathematical expressions][prev], you will want to represent
6+
the input as an *abstract syntax tree*, or AST (for a real-life
7+
example, see [Twig][twig-ast] or [Gherkin][gherkin-ast]).
8+
9+
Getting the AST of the input with Dissect is nothing special; the
10+
callbacks in your grammar can return anything, so they might as well
11+
return AST nodes. Dissect however helps you by providing a simple base
12+
class for the different node types: `Dissect\Node\CommonNode`.
13+
14+
Let's say we want to create an AST for the mathematical expressions from
15+
the previous chapter. Since the input can consist of binary operations
16+
and integers, let's create a subclass for each case:
17+
18+
```php
19+
use Dissect\Node\CommonNode;
20+
use Dissect\Node\Node;
21+
22+
class BinaryExpressionNode extends CommonNode
23+
{
24+
const PLUS = 1;
25+
const TIMES = 2;
26+
const POWER = 3;
27+
28+
public function __construct(Node $left, $op, Node $right)
29+
{
30+
parent::__construct(['operator' => $op], [
31+
'left' => $left,
32+
'right' => $right,
33+
]);
34+
}
35+
36+
public function getLeft()
37+
{
38+
return $this->getNode('left');
39+
}
40+
41+
public function getRight()
42+
{
43+
return $this->getNode('right');
44+
}
45+
46+
public function getOperator()
47+
{
48+
return $this->getAttribute('operator');
49+
}
50+
}
51+
52+
class IntNode extends CommonNode
53+
{
54+
public function __construct($value)
55+
{
56+
parent::__construct(['value' => $value]);
57+
}
58+
59+
public function getValue()
60+
{
61+
return $this->getAttribute('value');
62+
}
63+
}
64+
```
65+
66+
The original constructor has two parameters, an array of child nodes and
67+
an array of node attributes. `Dissect\Node\Node` is an interface
68+
describing common operations for an AST node.
69+
70+
We can now easily modify the original grammar to build the AST:
71+
72+
```php
73+
$this('Additive')
74+
->is('Additive', '+', 'Multiplicative')
75+
->call(function ($l, $_, $r) {
76+
return new BinaryExpressionNode($l, BinaryExpressionNode::PLUS, $r);
77+
})
78+
79+
->is('Multiplicative');
80+
81+
$this('Multiplicative')
82+
->is('Multiplicative', '*', 'Power')
83+
->call(function ($l, $_, $r) {
84+
return new BinaryExpressionNode($l, BinaryExpressionNode::TIMES, $r);
85+
})
86+
87+
->is('Power');
88+
89+
$this('Power')
90+
->is('Primary', '**', 'Power')
91+
->call(function ($l, $_, $r) {
92+
return new BinaryExpressionNode($l, BinaryExpressionNode::POWER, $r);
93+
})
94+
95+
->is('Primary');
96+
97+
$this('Primary')
98+
->is('(', 'Additive', ')')
99+
->call(function ($_, $e, $_) {
100+
return $e;
101+
})
102+
103+
->is('INT')
104+
->call(function ($int) {
105+
return new IntNode((int)$int->getValue());
106+
});
107+
```
108+
109+
Traversing the AST
110+
------------------
111+
112+
When we have the AST of our input, we want to interpret it somehow.
113+
The most common way to do this is to create a *node visitor* (sometimes
114+
called a *tree walker*). A trivial node visitor for our example could be
115+
the following recursive function:
116+
117+
```php
118+
function visit(Node $node)
119+
{
120+
if ($node instanceof BinaryExpressionNode) {
121+
switch ($node->getOperator()) {
122+
case BinaryExpressionNode::PLUS:
123+
return visit($node->getLeft()) + visit($node->getRight());
124+
case BinaryExpressionNode::TIMES:
125+
return visit($node->getLeft()) * visit($node->getRight());
126+
case BinaryExpressionNode::POWER:
127+
return pow(visit($node->getLeft()), visit($node->getRight());
128+
}
129+
} elseif ($node instanceof IntNode) {
130+
return $node->getValue();
131+
} else {
132+
throw new \Exception("Unknown node type.");
133+
}
134+
}
135+
136+
echo visit($parser->parse(...));
137+
```
138+
139+
[prev]: parsing.md#example-parsing-mathematical-expressions
140+
[twig-ast]: https://github.com/fabpot/Twig/tree/master/lib/Twig/Node
141+
[gherkin-ast]: https://github.com/Behat/Gherkin/tree/master/src/Behat/Gherkin/Node

0 commit comments

Comments
 (0)