The error token works now.

master
Richard van Velzen 2011-12-31 15:02:06 +01:00
parent 1b7c30f7b8
commit e68b476c09
10 changed files with 1014 additions and 480 deletions

View File

@ -1,438 +0,0 @@
<?php
/*
*** DON'T EDIT THIS FILE! ***
*
* This file was automatically generated by the Lime parser generator.
* The real source code you should be looking at is in one or more
* grammar files in the Lime format.
*
* THE ONLY REASON TO LOOK AT THIS FILE is to see where in the grammar
* file that your error happened, because there are enough comments to
* help you debug your grammar.
* If you ignore this warning, you're shooting yourself in the brain,
* not the foot.
*/
class calc extends lime_parser {
public $qi = 0;
public $i = array(
array(
'exp' => 's 1',
'var' => 's 23',
'num' => 's 3',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20',
'stmt' => 's 26',
"'start'" => "a 'start'"
),
array(
"'+'" => 's 2',
"'-'" => 's 6',
"'*'" => 's 8',
"'/'" => 's 10',
"'^'" => 's 12',
"'%'" => 's 14',
'#' => 'r 0'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 5',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 'r 2',
"'-'" => 'r 2',
"'*'" => 'r 2',
"'/'" => 'r 2',
"'^'" => 'r 2',
"'%'" => 'r 2',
"')'" => 'r 2',
'#' => 'r 2'
),
array(
"'+'" => 'r 3',
"'-'" => 'r 3',
"'*'" => 'r 3',
"'/'" => 'r 3',
"'^'" => 'r 3',
"'%'" => 'r 3',
"')'" => 'r 3',
'#' => 'r 3'
),
array(
"'+'" => 'r 4',
"'-'" => 'r 4',
"'*'" => 's 8',
"'/'" => 's 10',
"'^'" => 's 12',
"'%'" => 's 14',
"')'" => 'r 4',
'#' => 'r 4'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 7',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 'r 5',
"'-'" => 'r 5',
"'*'" => 's 8',
"'/'" => 's 10',
"'^'" => 's 12',
"'%'" => 's 14',
"')'" => 'r 5',
'#' => 'r 5'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 9',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 'r 6',
"'-'" => 'r 6',
"'*'" => 'r 6',
"'/'" => 'r 6',
"'^'" => 's 12',
"'%'" => 'r 6',
"')'" => 'r 6',
'#' => 'r 6'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 11',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 'r 7',
"'-'" => 'r 7',
"'*'" => 'r 7',
"'/'" => 'r 7',
"'^'" => 's 12',
"'%'" => 'r 7',
"')'" => 'r 7',
'#' => 'r 7'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 13',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 'r 8',
"'-'" => 'r 8',
"'*'" => 'r 8',
"'/'" => 'r 8',
"'^'" => 's 12',
"'%'" => 'r 8',
"')'" => 'r 8',
'#' => 'r 8'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 15',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 'r 9',
"'-'" => 'r 9',
"'*'" => 'r 9',
"'/'" => 'r 9',
"'^'" => 's 12',
"'%'" => 'r 9',
"')'" => 'r 9',
'#' => 'r 9'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 17',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 'r 10',
"'-'" => 'r 10',
"'*'" => 'r 10',
"'/'" => 'r 10',
"'^'" => 'r 10',
"'%'" => 'r 10',
"')'" => 'r 10',
'#' => 'r 10'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 19',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 'r 11',
"'-'" => 'r 11',
"'*'" => 'r 11',
"'/'" => 'r 11',
"'^'" => 'r 11',
"'%'" => 'r 11',
"')'" => 'r 11',
'#' => 'r 11'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 21',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 's 2',
"'-'" => 's 6',
"'*'" => 's 8',
"'/'" => 's 10',
"'^'" => 's 12',
"'%'" => 's 14',
"')'" => 's 22'
),
array(
"'%'" => 'r 12',
"'^'" => 'r 12',
"'/'" => 'r 12',
"'*'" => 'r 12',
"'-'" => 'r 12',
"'+'" => 'r 12',
"')'" => 'r 12',
'#' => 'r 12'
),
array(
"'='" => 's 24',
"'+'" => 'r 3',
"'-'" => 'r 3',
"'*'" => 'r 3',
"'/'" => 'r 3',
"'^'" => 'r 3',
"'%'" => 'r 3',
'#' => 'r 3'
),
array(
'exp' => 's 25',
'num' => 's 3',
'var' => 's 4',
"'+'" => 's 16',
"'-'" => 's 18',
"'('" => 's 20'
),
array(
"'+'" => 's 2',
"'-'" => 's 6',
"'*'" => 's 8',
"'/'" => 's 10',
"'^'" => 's 12',
"'%'" => 's 14',
'#' => 'r 1'
),
array(
'#' => 'r 13'
)
);
public $d = array(
"'+'" => 'plus sign (+)',
"'/'" => 'division (/)'
);
function reduce_0_stmt_1($tokens, &$result) {
// (0) stmt := exp
$result = reset($tokens);
echo " -> "; echo $tokens[0][0] . ' = ' . $tokens[0][1]; echo "\n";
}
function reduce_1_stmt_2($tokens, &$result) {
// (1) stmt := var '=' exp
$result = reset($tokens);
$v = &$tokens[0];
$e = &$tokens[2];
echo "$v = $e\n";
set_variable($v, $e);
}
function reduce_2_exp_1($tokens, &$result) {
// (2) exp := num
$result = reset($tokens);
$result = array($tokens[0], $tokens[0]);
}
function reduce_3_exp_2($tokens, &$result) {
// (3) exp := var
$result = reset($tokens);
$result = array($tokens[0], get_variable($tokens[0]));
}
function reduce_4_exp_3($tokens, &$result) {
// (4) exp := exp '+' exp
$result = reset($tokens);
$result = array('(' . $tokens[0][0] . ' + ' . $tokens[2][0] . ')', $tokens[0][1] + $tokens[2][1]);
}
function reduce_5_exp_4($tokens, &$result) {
// (5) exp := exp '-' exp
$result = reset($tokens);
$result = array('(' . $tokens[0][0] . ' - ' . $tokens[2][0] . ')', $tokens[0][1] - $tokens[2][1]);
}
function reduce_6_exp_5($tokens, &$result) {
// (6) exp := exp '*' exp
$result = reset($tokens);
$result = array('(' . $tokens[0][0] . ' * ' . $tokens[2][0] . ')', $tokens[0][1] * $tokens[2][1]);
}
function reduce_7_exp_6($tokens, &$result) {
// (7) exp := exp '/' exp
$result = reset($tokens);
$result = array('(' . $tokens[0][0] . ' / ' . $tokens[2][0] . ')', $tokens[0][1] / $tokens[2][1]);
}
function reduce_8_exp_7($tokens, &$result) {
// (8) exp := exp '^' exp
$result = reset($tokens);
$result = array('(' . $tokens[0][0] . ' ^ ' . $tokens[2][0] . ')', pow($tokens[0][1], $tokens[2][1]));
}
function reduce_9_exp_8($tokens, &$result) {
// (9) exp := exp '%' exp
$result = reset($tokens);
$result = array('(' . $tokens[0][0] . ' % ' . $tokens[2][0] . ')', $tokens[0][1] % $tokens[2][1]);
}
function reduce_10_exp_9($tokens, &$result) {
// (10) exp := '+' exp
$result = reset($tokens);
$result = array('(+ ' . $tokens[1][0] . ')', +($tokens[1][1]));
}
function reduce_11_exp_10($tokens, &$result) {
// (11) exp := '-' exp
$result = reset($tokens);
$result = array('(- ' . $tokens[1][0] . ')', -($tokens[1][1]));
}
function reduce_12_exp_11($tokens, &$result) {
// (12) exp := '(' exp ')'
$result = $tokens[1];
}
function reduce_13_start_1($tokens, &$result) {
// (13) 'start' := stmt
$result = reset($tokens);
}
public $method = array(
'reduce_0_stmt_1',
'reduce_1_stmt_2',
'reduce_2_exp_1',
'reduce_3_exp_2',
'reduce_4_exp_3',
'reduce_5_exp_4',
'reduce_6_exp_5',
'reduce_7_exp_6',
'reduce_8_exp_7',
'reduce_9_exp_8',
'reduce_10_exp_9',
'reduce_11_exp_10',
'reduce_12_exp_11',
'reduce_13_start_1'
);
public $a = array(
array(
'symbol' => 'stmt',
'len' => 1,
'replace' => true
),
array(
'symbol' => 'stmt',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 1,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 1,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 2,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 2,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => "'start'",
'len' => 1,
'replace' => true
)
);
}

View File

@ -1,31 +0,0 @@
%class calc
%start stmt
%token '+' "plus sign (+)"
%token '/' "division (/)"
%left '+' '-'
%left '*' '/' '%'
%right '^'
%right T_INC
stmt = exp { echo " -> "; echo $1[0] . ' = ' . $1[1]; echo "\n"; }
| var/v '=' exp/e {
echo "$v = $e\n";
set_variable($v, $e);
}
.
exp = num { $$ = array($1, $1); }
| var { $$ = array($1, get_variable($1)); }
| exp '+' exp { $$ = array('(' . $1[0] . ' + ' . $3[0] . ')', $1[1] + $3[1]); }
| exp '-' exp { $$ = array('(' . $1[0] . ' - ' . $3[0] . ')', $1[1] - $3[1]); }
| exp '*' exp { $$ = array('(' . $1[0] . ' * ' . $3[0] . ')', $1[1] * $3[1]); }
| exp '/' exp { $$ = array('(' . $1[0] . ' / ' . $3[0] . ')', $1[1] / $3[1]); }
| exp '^' exp { $$ = array('(' . $1[0] . ' ^ ' . $3[0] . ')', pow($1[1], $3[1])); }
| exp '%' exp { $$ = array('(' . $1[0] . ' % ' . $3[0] . ')', $1[1] % $3[1]); }
| '+' exp %prec T_INC { $$ = array('(+ ' . $2[0] . ')', +($2[1])); }
| '-' exp %prec T_INC { $$ = array('(- ' . $2[0] . ')', -($2[1])); }
| '(' exp/$ ')'
.

664
examples/calc/calc.class Normal file
View File

@ -0,0 +1,664 @@
<?php
/*
*** DON'T EDIT THIS FILE! ***
*
* This file was automatically generated by the Lime parser generator.
* The real source code you should be looking at is in one or more
* grammar files in the Lime format.
*
* THE ONLY REASON TO LOOK AT THIS FILE is to see where in the grammar
* file that your error happened, because there are enough comments to
* help you debug your grammar.
* If you ignore this warning, you're shooting yourself in the brain,
* not the foot.
*/
class calc extends lime_parser {
public $qi = 0;
public $i = array(
array(
'exp' => 's 1',
'var' => 's 31',
'num' => 's 3',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24',
'stmt' => 's 34',
"'start'" => "a 'start'"
),
array(
"'+'" => 's 2',
"'-'" => 's 7',
"'*'" => 's 9',
"'/'" => 's 11',
"'^'" => 's 13',
"'%'" => 's 15',
'#' => 'r 0'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 30',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 'r 2',
"'-'" => 'r 2',
"'*'" => 'r 2',
"'/'" => 'r 2',
"'^'" => 'r 2',
"'%'" => 'r 2',
"')'" => 'r 2',
"','" => 'r 2',
'#' => 'r 2'
),
array(
"'('" => 's 5',
"'+'" => 'r 3',
"'-'" => 'r 3',
"'*'" => 'r 3',
"'/'" => 'r 3',
"'^'" => 'r 3',
"'%'" => 'r 3',
"')'" => 'r 3',
"','" => 'r 3',
'#' => 'r 3'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 6',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'param_list' => 's 25',
'error' => 's 24',
'non_empty_param_list' => 's 27',
"')'" => 'r 15'
),
array(
"'+'" => 's 2',
"'-'" => 's 7',
"'*'" => 's 9',
"'/'" => 's 11',
"'^'" => 's 13',
"'%'" => 's 15',
"','" => 'r 17',
"')'" => 'r 17'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 8',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 'r 5',
"'-'" => 'r 5',
"'*'" => 's 9',
"'/'" => 's 11',
"'^'" => 's 13',
"'%'" => 's 15',
"')'" => 'r 5',
"','" => 'r 5',
'#' => 'r 5'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 10',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 'r 6',
"'-'" => 'r 6',
"'*'" => 'r 6',
"'/'" => 'r 6',
"'^'" => 's 13',
"'%'" => 'r 6',
"')'" => 'r 6',
"','" => 'r 6',
'#' => 'r 6'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 12',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 'r 7',
"'-'" => 'r 7',
"'*'" => 'r 7',
"'/'" => 'r 7',
"'^'" => 's 13',
"'%'" => 'r 7',
"')'" => 'r 7',
"','" => 'r 7',
'#' => 'r 7'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 14',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 'r 8',
"'-'" => 'r 8',
"'*'" => 'r 8',
"'/'" => 'r 8',
"'^'" => 's 13',
"'%'" => 'r 8',
"')'" => 'r 8',
"','" => 'r 8',
'#' => 'r 8'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 16',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 'r 9',
"'-'" => 'r 9',
"'*'" => 'r 9',
"'/'" => 'r 9',
"'^'" => 's 13',
"'%'" => 'r 9',
"')'" => 'r 9',
"','" => 'r 9',
'#' => 'r 9'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 18',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 'r 10',
"'-'" => 'r 10',
"'*'" => 'r 10',
"'/'" => 'r 10',
"'^'" => 'r 10',
"'%'" => 'r 10',
"')'" => 'r 10',
"','" => 'r 10',
'#' => 'r 10'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 20',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 'r 11',
"'-'" => 'r 11',
"'*'" => 'r 11',
"'/'" => 'r 11',
"'^'" => 'r 11',
"'%'" => 'r 11',
"')'" => 'r 11',
"','" => 'r 11',
'#' => 'r 11'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 22',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 's 2',
"'-'" => 's 7',
"'*'" => 's 9',
"'/'" => 's 11',
"'^'" => 's 13',
"'%'" => 's 15',
"')'" => 's 23'
),
array(
"'%'" => 'r 12',
"'^'" => 'r 12',
"'/'" => 'r 12',
"'*'" => 'r 12',
"'-'" => 'r 12',
"'+'" => 'r 12',
"')'" => 'r 12',
"','" => 'r 12',
'#' => 'r 12'
),
array(
"'%'" => 'r 14',
"'^'" => 'r 14',
"'/'" => 'r 14',
"'*'" => 'r 14',
"'-'" => 'r 14',
"'+'" => 'r 14',
"')'" => 'r 14',
"','" => 'r 14',
'#' => 'r 14'
),
array(
"')'" => 's 26'
),
array(
"'%'" => 'r 13',
"'^'" => 'r 13',
"'/'" => 'r 13',
"'*'" => 'r 13',
"'-'" => 'r 13',
"'+'" => 'r 13',
"')'" => 'r 13',
"','" => 'r 13',
'#' => 'r 13'
),
array(
"','" => 's 28',
"')'" => 'r 16'
),
array(
'num' => 's 3',
'var' => 's 4',
'exp' => 's 29',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 's 2',
"'-'" => 's 7',
"'*'" => 's 9',
"'/'" => 's 11',
"'^'" => 's 13',
"'%'" => 's 15',
"','" => 'r 18',
"')'" => 'r 18'
),
array(
"'+'" => 'r 4',
"'-'" => 'r 4',
"'*'" => 's 9',
"'/'" => 's 11',
"'^'" => 's 13',
"'%'" => 's 15',
"')'" => 'r 4',
"','" => 'r 4',
'#' => 'r 4'
),
array(
"'='" => 's 32',
"'('" => 's 5',
"'+'" => 'r 3',
"'-'" => 'r 3',
"'*'" => 'r 3',
"'/'" => 'r 3',
"'^'" => 'r 3',
"'%'" => 'r 3',
'#' => 'r 3'
),
array(
'exp' => 's 33',
'num' => 's 3',
'var' => 's 4',
"'+'" => 's 17',
"'-'" => 's 19',
"'('" => 's 21',
'error' => 's 24'
),
array(
"'+'" => 's 2',
"'-'" => 's 7',
"'*'" => 's 9',
"'/'" => 's 11',
"'^'" => 's 13',
"'%'" => 's 15',
'#' => 'r 1'
),
array(
'#' => 'r 19'
)
);
public $d = array(
"'+'" => 'plus operator (+)',
"'-'" => 'minus operator (-)',
"'*'" => 'multiplication operator (*)',
"'/'" => 'division operator (/)',
"'%'" => 'modulo operator (%)',
"'^'" => 'exponentiation operator (^)'
);
function reduce_0_stmt_1($tokens, &$result) {
// (0) stmt := exp
$result = reset($tokens);
echo ' -> ';
echo $tokens[0][0] . ' = ' . $tokens[0][1];
echo "\n";
}
function reduce_1_stmt_2($tokens, &$result) {
// (1) stmt := var '=' exp
$result = reset($tokens);
$v = &$tokens[0];
$e = &$tokens[2];
echo $v . ' = ' . $e . "\n";
set_variable($v, $e);
}
function reduce_2_exp_1($tokens, &$result) {
// (2) exp := num
$result = reset($tokens);
$result = array($tokens[0], $tokens[0]);
}
function reduce_3_exp_2($tokens, &$result) {
// (3) exp := var
$result = reset($tokens);
$result = array($tokens[0], get_variable($tokens[0]));
}
function reduce_4_exp_3($tokens, &$result) {
// (4) exp := exp '+' exp
$result = reset($tokens);
$result = array(
'(' . $tokens[0][0] . ' + ' . $tokens[2][0] . ')',
nan_or($tokens[0][1], $tokens[2][1], $tokens[0][1] + $tokens[2][1])
);
}
function reduce_5_exp_4($tokens, &$result) {
// (5) exp := exp '-' exp
$result = reset($tokens);
$result = array(
'(' . $tokens[0][0] . ' - ' . $tokens[2][0] . ')',
nan_or($tokens[0][1], $tokens[2][1], $tokens[0][1] - $tokens[2][1])
);
}
function reduce_6_exp_5($tokens, &$result) {
// (6) exp := exp '*' exp
$result = reset($tokens);
$result = array(
'(' . $tokens[0][0] . ' * ' . $tokens[2][0] . ')',
nan_or($tokens[0][1], $tokens[2][1], $tokens[0][1] * $tokens[2][1])
);
}
function reduce_7_exp_6($tokens, &$result) {
// (7) exp := exp '/' exp
$result = reset($tokens);
$result = array(
'(' . $tokens[0][0] . ' / ' . $tokens[2][0] . ')',
nan_or($tokens[0][1], $tokens[2][1], $tokens[0][1] / $tokens[2][1])
);
}
function reduce_8_exp_7($tokens, &$result) {
// (8) exp := exp '^' exp
$result = reset($tokens);
$result = array(
'(' . $tokens[0][0] . ' ^ ' . $tokens[2][0] . ')',
nan_or($tokens[0][1], $tokens[2][1], pow($tokens[0][1], $tokens[2][1]))
);
}
function reduce_9_exp_8($tokens, &$result) {
// (9) exp := exp '%' exp
$result = reset($tokens);
$result = array(
'(' . $tokens[0][0] . ' % ' . $tokens[2][0] . ')',
nan_or($tokens[0][1], $tokens[2][1], $tokens[0][1] % $tokens[2][1])
);
}
function reduce_10_exp_9($tokens, &$result) {
// (10) exp := '+' exp
$result = reset($tokens);
$result = array(
'(+ ' . $tokens[1][0] . ')',
nan_or($tokens[0][1], $tokens[2][1], +($tokens[1][1]))
);
}
function reduce_11_exp_10($tokens, &$result) {
// (11) exp := '-' exp
$result = reset($tokens);
$result = array(
'(- ' . $tokens[1][0] . ')',
nan_or($tokens[0][1], $tokens[2][1], -($tokens[1][1]))
);
}
function reduce_12_exp_11($tokens, &$result) {
// (12) exp := '(' exp ')'
$result = $tokens[1];
}
function reduce_13_exp_12($tokens, &$result) {
// (13) exp := var '(' param_list ')'
$result = reset($tokens);
$result = array(
// little bits of voodoo to make this happen
'(' . $tokens[0] . '(' .
implode(', ', array_map(function ($a) {
return $a[0];
}, $tokens[2])) .
'))',
call_user_func_array($tokens[0], array_map(function ($a) {
return $a[1];
}, $tokens[2]))
);
}
function reduce_14_exp_13($tokens, &$result) {
// (14) exp := error
$result = reset($tokens);
printf("Error\n");
$result = array('NaN', NaN);
}
function reduce_15_param_list_1($tokens, &$result) {
// (15) param_list :=
$result = reset($tokens);
$result = array();
}
function reduce_16_param_list_2($tokens, &$result) {
// (16) param_list := non_empty_param_list
$result = reset($tokens);
}
function reduce_17_non_empty_param_list_1($tokens, &$result) {
// (17) non_empty_param_list := exp
$result = reset($tokens);
$result = array($tokens[0]);
}
function reduce_18_non_empty_param_list_2($tokens, &$result) {
// (18) non_empty_param_list := non_empty_param_list ',' exp
$result = reset($tokens);
$tokens[0][] = $tokens[2];
$result = $tokens[0];
}
function reduce_19_start_1($tokens, &$result) {
// (19) 'start' := stmt
$result = reset($tokens);
}
public $method = array(
'reduce_0_stmt_1',
'reduce_1_stmt_2',
'reduce_2_exp_1',
'reduce_3_exp_2',
'reduce_4_exp_3',
'reduce_5_exp_4',
'reduce_6_exp_5',
'reduce_7_exp_6',
'reduce_8_exp_7',
'reduce_9_exp_8',
'reduce_10_exp_9',
'reduce_11_exp_10',
'reduce_12_exp_11',
'reduce_13_exp_12',
'reduce_14_exp_13',
'reduce_15_param_list_1',
'reduce_16_param_list_2',
'reduce_17_non_empty_param_list_1',
'reduce_18_non_empty_param_list_2',
'reduce_19_start_1'
);
public $a = array(
array(
'symbol' => 'stmt',
'len' => 1,
'replace' => true
),
array(
'symbol' => 'stmt',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 1,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 1,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 2,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 2,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 4,
'replace' => true
),
array(
'symbol' => 'exp',
'len' => 1,
'replace' => true
),
array(
'symbol' => 'param_list',
'len' => 0,
'replace' => true
),
array(
'symbol' => 'param_list',
'len' => 1,
'replace' => true
),
array(
'symbol' => 'non_empty_param_list',
'len' => 1,
'replace' => true
),
array(
'symbol' => 'non_empty_param_list',
'len' => 3,
'replace' => true
),
array(
'symbol' => "'start'",
'len' => 1,
'replace' => true
)
);
}
// Time: 0.12659001350403 seconds
// Memory: 2765212 bytes

117
examples/calc/calc.lime Normal file
View File

@ -0,0 +1,117 @@
%class calc
%start stmt
%token '+' "plus operator (+)"
%token '-' "minus operator (-)"
%token '*' "multiplication operator (*)"
%token '/' "division operator (/)"
%token '%' "modulo operator (%)"
%token '^' "exponentiation operator (^)"
%left '+' '-'
%left '*' '/' '%'
%right '^'
%right T_INC
stmt = exp {
echo ' -> ';
echo $1[0] . ' = ' . $1[1];
echo "\n";
}
| var/v '=' exp/e {
echo $v . ' = ' . $e . "\n";
set_variable($v, $e);
}
.
exp = num {
$$ = array($1, $1);
}
| var {
$$ = array($1, get_variable($1));
}
| exp '+' exp {
$$ = array(
'(' . $1[0] . ' + ' . $3[0] . ')',
nan_or($1[1], $3[1], $1[1] + $3[1])
);
}
| exp '-' exp {
$$ = array(
'(' . $1[0] . ' - ' . $3[0] . ')',
nan_or($1[1], $3[1], $1[1] - $3[1])
);
}
| exp '*' exp {
$$ = array(
'(' . $1[0] . ' * ' . $3[0] . ')',
nan_or($1[1], $3[1], $1[1] * $3[1])
);
}
| exp '/' exp {
$$ = array(
'(' . $1[0] . ' / ' . $3[0] . ')',
nan_or($1[1], $3[1], $1[1] / $3[1])
);
}
| exp '^' exp {
$$ = array(
'(' . $1[0] . ' ^ ' . $3[0] . ')',
nan_or($1[1], $3[1], pow($1[1], $3[1]))
);
}
| exp '%' exp {
$$ = array(
'(' . $1[0] . ' % ' . $3[0] . ')',
nan_or($1[1], $3[1], $1[1] % $3[1])
);
}
| '+' exp %prec T_INC {
$$ = array(
'(+ ' . $2[0] . ')',
nan_or($1[1], $3[1], +($2[1]))
);
}
| '-' exp %prec T_INC {
$$ = array(
'(- ' . $2[0] . ')',
nan_or($1[1], $3[1], -($2[1]))
);
}
| '(' exp/$ ')'
| var '(' param_list ')' {
$$ = array(
// little bits of voodoo to make this happen
'(' . $1 . '(' .
implode(', ', array_map(function ($a) {
return $a[0];
}, $3)) .
'))',
call_user_func_array($1, array_map(function ($a) {
return $a[1];
}, $3))
);
}
| error {
printf("Error\n");
$$ = array('NaN', NaN);
}
.
param_list:
/* empty */ {
$$ = array();
}
| non_empty_param_list
.
non_empty_param_list:
exp {
$$ = array($1);
}
| non_empty_param_list ',' exp {
$1[] = $3;
$$ = $1;
}
.

View File

@ -6,10 +6,12 @@ and use it in another calculation like:
<?
include_once "../parse_engine.php";
include_once "../../parse_engine.php";
include_once "calc.class";
function nan_or($l, $r, $or) {
return !is_numeric($l) || !is_numeric($r) || is_nan($l) || is_nan($r) ? NaN : $or;
}
function tokenize($line) {
// Numbers are tokens, as are all other non-whitespace characters.

152
examples/error/error.class Normal file
View File

@ -0,0 +1,152 @@
<?php
/*
*** DON'T EDIT THIS FILE! ***
*
* This file was automatically generated by the Lime parser generator.
* The real source code you should be looking at is in one or more
* grammar files in the Lime format.
*
* THE ONLY REASON TO LOOK AT THIS FILE is to see where in the grammar
* file that your error happened, because there are enough comments to
* help you debug your grammar.
* If you ignore this warning, you're shooting yourself in the brain,
* not the foot.
*/
class parser extends lime_parser {
public $qi = 0;
public $i = array(
array(
'slist' => 's 1',
'stmt' => 's 6',
'error' => 's 8',
'ZZ' => 's 4',
"'start'" => "a 'start'"
),
array(
'stmt' => 's 2',
'ZZ' => 's 4',
'#' => 'r 5'
),
array(
"';'" => 's 3'
),
array(
'ZZ' => 'r 0',
'#' => 'r 0'
),
array(
'ZZ' => 's 4',
'stmt' => 's 5',
"';'" => 'r 4'
),
array(
"';'" => 'r 3'
),
array(
"';'" => 's 7'
),
array(
'ZZ' => 'r 1',
'#' => 'r 1'
),
array(
"';'" => 's 9'
),
array(
'ZZ' => 'r 2',
'#' => 'r 2'
)
);
public $d = array(
);
function reduce_0_slist_1($tokens, &$result) {
// (0) slist := slist stmt ';'
$result = reset($tokens);
printf("slist stmt\n");
$result = array($tokens[0], $tokens[1]);
}
function reduce_1_slist_2($tokens, &$result) {
// (1) slist := stmt ';'
$result = reset($tokens);
printf("stmt\n");
$result = $tokens[0];
}
function reduce_2_slist_3($tokens, &$result) {
// (2) slist := error ';'
$result = reset($tokens);
printf("error\n");
$result = 'error';
}
function reduce_3_stmt_1($tokens, &$result) {
// (3) stmt := ZZ stmt
$result = reset($tokens);
printf("ZZ stmt\n");
$result = array($tokens[0], $tokens[1]);
}
function reduce_4_stmt_2($tokens, &$result) {
// (4) stmt := ZZ
$result = reset($tokens);
printf("ZZ\n");
$result = array($tokens[0]);
}
function reduce_5_start_1($tokens, &$result) {
// (5) 'start' := slist
$result = reset($tokens);
}
public $method = array(
'reduce_0_slist_1',
'reduce_1_slist_2',
'reduce_2_slist_3',
'reduce_3_stmt_1',
'reduce_4_stmt_2',
'reduce_5_start_1'
);
public $a = array(
array(
'symbol' => 'slist',
'len' => 3,
'replace' => true
),
array(
'symbol' => 'slist',
'len' => 2,
'replace' => true
),
array(
'symbol' => 'slist',
'len' => 2,
'replace' => true
),
array(
'symbol' => 'stmt',
'len' => 2,
'replace' => true
),
array(
'symbol' => 'stmt',
'len' => 1,
'replace' => true
),
array(
'symbol' => "'start'",
'len' => 1,
'replace' => true
)
);
}
// Time: 0.039383888244629 seconds
// Memory: 1514364 bytes

27
examples/error/error.lime Normal file
View File

@ -0,0 +1,27 @@
#program: slist { var_dump($1); $$ = $1; };
slist:
slist stmt ';' {
printf("slist stmt\n");
$$ = array($1, $2);
}
| stmt ';' {
printf("stmt\n");
$$ = $1;
}
| error ';' {
printf("error\n");
$$ = 'error';
}
;
stmt:
ZZ stmt {
printf("ZZ stmt\n");
$$ = array($1, $2);
}
| ZZ {
printf("ZZ\n");
$$ = array($1);
}
;

29
examples/error/error.php Normal file
View File

@ -0,0 +1,29 @@
<?php
include_once "../../parse_engine.php";
include_once "error.class";
$parser = new parse_engine(new parser());
//$parser->debug = true;
$tokens = array(
array('ZZ', 'zz'),
array('ZZ', 'zz'),
array('YY', 'yy'),
';',
array('ZZ', 'zz'),
array('ZZ', 'zz'),
';'
);
foreach($tokens as $token) {
if (is_array($token)) {
$parser->eat($token[0], $token[1]);
} else {
$parser->eat("'{$token}'", $token);
}
}
$parser->eat_eof();
var_dump($parser->semantic);
var_dump($parser->errors);

View File

@ -470,7 +470,7 @@ class rule {
$symbol_after_the_dot = $this->rhs[$dot];
$first = $symbol_after_the_dot->first->all();
bug_if(empty($first) and !$symbol_after_the_dot->lambda);
bug_if(empty($first) and !$symbol_after_the_dot->lambda and $symbol_after_the_dot->name != 'error');
$set = new set($first);
if ($symbol_after_the_dot->lambda) {

View File

@ -102,11 +102,14 @@ class parse_stack {
}
class parse_engine {
public $debug = false;
public $parser;
public $qi;
public $rule;
public $step;
public $descr;
public $errors = array();
/**
* @var boolean
*/
@ -129,6 +132,7 @@ class parse_engine {
public function reset() {
$this->accept = false;
$this->stack = new parse_stack($this->qi);
$this->errors = array();
}
private function enter_error_tolerant_state() {
@ -137,6 +141,9 @@ class parse_engine {
return true;
}
if ($this->debug) echo "Dropped an item from the stack, {" . implode(', ', $this->get_steps()) . "} left\n";
if ($this->debug) echo 'Currently in state ' . $this->state() . "\n";
$this->drop();
}
@ -225,7 +232,7 @@ class parse_engine {
$expect = $this->get_steps();
while ($this->enter_error_tolerant_state()) {
while ($this->enter_error_tolerant_state() || $this->has_step_for('error')) {
if (isset($seen[$this->state()])) {
// This means that it's pointless to try here.
// We're guaranteed that the stack is occupied.
@ -235,7 +242,7 @@ class parse_engine {
$seen[$this->state()] = true;
$this->eat('error', null);
$this->eat('error', 'Premature EOF');
if ($this->has_step_for('#')) {
// Good. We can continue as normal.
@ -293,16 +300,17 @@ class parse_engine {
function eat($type, $semantic) {
// assert('$type == trim($type)');
// if ($this->debug) echo "Trying to eat a ($type)\n";
if ($this->debug) echo "Trying to eat a ($type)\n";
list($opcode, $operand) = $this->step_for($type);
switch ($opcode) {
case 's':
// if ($this->debug) echo "shift $type to state $operand\n";
if ($this->debug) echo "shift $type to state $operand\n";
$this->stack->shift($operand, $semantic);
// echo $this->stack->text()." shift $type<br/>\n";
break;
case 'r':
if ($this->debug) echo "Reducing $type via rule $operand\n";
$this->reduce($operand);
$this->eat($type, $semantic);
// Yes, this is tail-recursive. It's also the simplest way.
@ -313,20 +321,24 @@ class parse_engine {
}
$this->accept = true;
//if ($this->debug) echo ("Accept\n\n");
if ($this->debug) echo ("Accept\n\n");
$this->semantic = $semantic;
break;
case 'e':
// This is thought to be the uncommon, exceptional path, so
// it's OK that this algorithm will cause the stack to
// flutter while the parse engine waits for an edible token.
// if ($this->debug) echo "($type) causes a problem.\n";
if ($this->debug) echo "($type) causes a problem.\n";
// get these before doing anything
$expected = $this->get_steps();
if ($this->enter_error_tolerant_state()) {
$this->eat('error', null);
$this->errors[] = $this->descr($type, $semantic) . ' not expected, expected {' . implode(', ', $expected) . '}';
if ($this->debug) echo "Possibilities before error fixing: {" . implode(', ', $expected) . "}\n";
if ($this->enter_error_tolerant_state() || $this->has_step_for('error')) {
$this->eat('error', end($this->errors));
if ($this->has_step_for($type)) {
$this->eat($type, $semantic);
}