acf
This commit is contained in:
152
plugins/system/nrframework/NRFramework/Parser/Parser.php
Normal file
152
plugins/system/nrframework/NRFramework/Parser/Parser.php
Normal file
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author Tassos.gr <info@tassos.gr>
|
||||
* @link https://www.tassos.gr
|
||||
* @copyright Copyright © 2024 Tassos All Rights Reserved
|
||||
* @license GNU GPLv3 <http://www.gnu.org/licenses/gpl.html> or later
|
||||
*/
|
||||
|
||||
namespace NRFramework\Parser;
|
||||
|
||||
defined('_JEXEC') or die;
|
||||
|
||||
use NRFramework\Parser\Lexer;
|
||||
use NRFramework\Parser\RingBuffer;
|
||||
|
||||
/**
|
||||
* Parser base class
|
||||
* LL(k) recursive-decent parser with backtracking support
|
||||
*/
|
||||
abstract class Parser
|
||||
{
|
||||
/**
|
||||
* Lexer instance (feeds the parser with tokens)
|
||||
*
|
||||
* @var NRFramework\Parser\Lexer
|
||||
*/
|
||||
protected $input = null;
|
||||
|
||||
/**
|
||||
* Ring buffer of the next k tokens
|
||||
* from the input stream
|
||||
*
|
||||
* @var RingBuffer
|
||||
*/
|
||||
protected $lookahead = null;
|
||||
|
||||
/**
|
||||
* k: Number of lookahead tokens
|
||||
*
|
||||
* @var int
|
||||
*/
|
||||
protected $k;
|
||||
|
||||
/**
|
||||
* Array(stack) containing the current
|
||||
* contents of the lookahead buffer when
|
||||
* marking the position of the stream
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $lookahead_history = null;
|
||||
|
||||
/**
|
||||
* Lexer constructor
|
||||
*
|
||||
* @param Lexer $input
|
||||
* @param integer $k, number of lookahead tokens
|
||||
*/
|
||||
public function __construct(Lexer $input, $k = 1)
|
||||
{
|
||||
if (!is_integer($k) || ($k < 1))
|
||||
{
|
||||
throw new \InvalidArgumentException('Parser: $k must be greater than 0!');
|
||||
}
|
||||
$this->k = $k;
|
||||
$this->input = $input;
|
||||
$this->lookahead_history = [];
|
||||
|
||||
// initialize lookahead buffer
|
||||
$this->resetBuffer();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks the type of the next token.
|
||||
* Advances the position in the token stream.
|
||||
*
|
||||
* @param string $type
|
||||
* @return void
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function match($type)
|
||||
{
|
||||
if ($this->lookahead[0]->type === $type)
|
||||
{
|
||||
$this->consume();
|
||||
return;
|
||||
}
|
||||
|
||||
throw new Exceptions\SyntaxErrorException('Expecting token ' . $type . ', found ' . $this->lookahead[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the next token from the input stream
|
||||
* and add it to the buffer.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function consume()
|
||||
{
|
||||
$this->lookahead[] = $this->input->nextToken();
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the position in the token stream
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mark()
|
||||
{
|
||||
array_push($this->lookahead_history, $this->lookahead);
|
||||
$this->input->mark();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset to a previously marked position
|
||||
* in the token stream
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->input->reset();
|
||||
|
||||
// reset lookahead buffer if not marked
|
||||
if (empty($this->lookahead_history))
|
||||
{
|
||||
$this->resetBuffer();
|
||||
}
|
||||
// normal reset
|
||||
else
|
||||
{
|
||||
$this->lookahead = array_pop($this->lookahead_history);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets and refills the lookahead buffer starting
|
||||
* from the current position in the token stream
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function resetBuffer()
|
||||
{
|
||||
$this->lookahead = new RingBuffer($this->k);
|
||||
for ($i=0; $i < $this->k; $i++)
|
||||
{
|
||||
$this->consume();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user