First   A
last analyzed

Complexity

Total Complexity 13

Size/Duplication

Total Lines 75
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 22
dl 0
loc 75
rs 10
c 0
b 0
f 0
wmc 13

6 Methods

Rating   Name   Duplication   Size   Complexity  
A getProductionTokens() 0 10 3
A addEpsilon() 0 7 2
A mergeProductionEpsilons() 0 4 2
A hasEpsilon() 0 3 1
A mergeProductionTokens() 0 3 1
A productionHasEpsilon() 0 11 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Remorhaz\UniLex\Parser\LL1\Lookup;
6
7
/**
8
 * Helper to calculate FIRST() sets. It's a part of LL(1) lookup table generation algorithm. FIRST(X) set
9
 * contains terminals (and, optionally, ε-production) that can occur as a starting token in production X.
10
 */
11
class First extends Set implements FirstInterface
12
{
13
    private $epsilonMap = [];
14
15
    /**
16
     * Returns FIRST(X) set.
17
     *
18
     * @param int ...$symbolIdList
19
     * @return array
20
     */
21
    public function getProductionTokens(int ...$symbolIdList): array
22
    {
23
        $first = [];
24
        foreach ($symbolIdList as $symbolId) {
25
            $first = array_merge($first, $this->getTokens($symbolId));
26
            if (!$this->productionHasEpsilon($symbolId)) {
27
                break;
28
            }
29
        }
30
        return $first;
31
    }
32
33
    /**
34
     * Adds ε-production to FIRST(X) set.
35
     *
36
     * @param int $symbolId
37
     */
38
    public function addEpsilon(int $symbolId): void
39
    {
40
        if ($this->hasEpsilon($symbolId)) {
41
            return;
42
        }
43
        $this->epsilonMap[$symbolId] = true;
44
        $this->increaseChangeCount();
45
    }
46
47
    /**
48
     * Reports presence of ε-production in FIRST(X) sets for all given X.
49
     *
50
     * @param int ...$symbolIdList
51
     * @return bool
52
     */
53
    public function productionHasEpsilon(int ...$symbolIdList): bool
54
    {
55
        if (empty($symbolIdList)) {
56
            return true;
57
        }
58
        foreach ($symbolIdList as $symbolId) {
59
            if (!$this->hasEpsilon($symbolId)) {
60
                return false;
61
            }
62
        }
63
        return true;
64
    }
65
66
    public function hasEpsilon(int $symbolId)
67
    {
68
        return $this->epsilonMap[$symbolId] ?? false;
69
    }
70
71
    /**
72
     * Adds all tokens from source production's FIRST(X) to target production's FIRST(Y).
73
     *
74
     * @param int $targetSymbolId
75
     * @param int ...$sourceSymbolIdList
76
     */
77
    public function mergeProductionTokens(int $targetSymbolId, int ...$sourceSymbolIdList): void
78
    {
79
        $this->addToken($targetSymbolId, ...$this->getProductionTokens(...$sourceSymbolIdList));
80
    }
81
82
    public function mergeProductionEpsilons(int $targetSymbolId, int ...$sourceSymbolIdList): void
83
    {
84
        if ($this->productionHasEpsilon(...$sourceSymbolIdList)) {
85
            $this->addEpsilon($targetSymbolId);
86
        }
87
    }
88
}
89