FollowBuilder   A
last analyzed

Complexity

Total Complexity 10

Size/Duplication

Total Lines 55
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 25
dl 0
loc 55
rs 10
c 0
b 0
f 0
wmc 10

5 Methods

Rating   Name   Duplication   Size   Complexity  
A mergeProduction() 0 9 3
A mergeProductionsFromNonTerminalMap() 0 4 2
A getFollow() 0 12 3
A __construct() 0 4 1
A addStartSymbol() 0 3 1
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\UniLex\Parser\LL1\Lookup;
6
7
use Remorhaz\UniLex\Grammar\ContextFree\GrammarInterface;
8
use Remorhaz\UniLex\Grammar\ContextFree\Production;
9
10
class FollowBuilder
11
{
12
    private $grammar;
13
14
    private $first;
15
16
    private $follow;
17
18
    public function __construct(GrammarInterface $grammar, FirstInterface $first)
19
    {
20
        $this->grammar = $grammar;
21
        $this->first = $first;
22
    }
23
24
    /**
25
     * @return Follow
26
     */
27
    public function getFollow(): Follow
28
    {
29
        if (!isset($this->follow)) {
30
            $follow = new Follow();
31
            $this->addStartSymbol($follow);
32
            do {
33
                $follow->resetChangeCount();
34
                $this->mergeProductionsFromNonTerminalMap($follow);
35
            } while ($follow->getChangeCount() > 0);
36
            $this->follow = $follow;
37
        }
38
        return $this->follow;
39
    }
40
41
    private function addStartSymbol(Follow $follow): void
42
    {
43
        $follow->addToken($this->grammar->getStartSymbol(), $this->grammar->getEoiSymbol());
44
    }
45
46
    /**
47
     * @param Follow $follow
48
     */
49
    private function mergeProductionsFromNonTerminalMap(Follow $follow): void
50
    {
51
        foreach ($this->grammar->getFullProductionList() as $production) {
52
            $this->mergeProduction($follow, $production);
53
        }
54
    }
55
56
    private function mergeProduction(Follow $follow, Production $production): void
57
    {
58
        $symbolIdList = $production->getSymbolList();
59
        while (!empty($symbolIdList)) {
60
            $targetSymbolId = array_shift($symbolIdList);
61
            $rightPartFirst = $this->first->getProductionTokens(...$symbolIdList);
62
            $follow->addToken($targetSymbolId, ...$rightPartFirst);
63
            if ($this->first->productionHasEpsilon(...$symbolIdList)) {
64
                $follow->mergeTokens($targetSymbolId, $production->getHeaderId());
65
            }
66
        };
67
    }
68
}
69