From e68b476c09cb0d911482cdc0caae5dd3c9318c1b Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Sat, 31 Dec 2011 15:02:06 +0100 Subject: [PATCH] The error token works now. --- examples/calc.class | 438 ----------------------- examples/calc.lime | 31 -- examples/calc/calc.class | 664 +++++++++++++++++++++++++++++++++++ examples/calc/calc.lime | 117 ++++++ examples/{ => calc}/calc.php | 6 +- examples/error/error.class | 152 ++++++++ examples/error/error.lime | 27 ++ examples/error/error.php | 29 ++ lime.php | 2 +- parse_engine.php | 28 +- 10 files changed, 1014 insertions(+), 480 deletions(-) delete mode 100644 examples/calc.class delete mode 100644 examples/calc.lime create mode 100644 examples/calc/calc.class create mode 100644 examples/calc/calc.lime rename examples/{ => calc}/calc.php (90%) create mode 100644 examples/error/error.class create mode 100644 examples/error/error.lime create mode 100644 examples/error/error.php diff --git a/examples/calc.class b/examples/calc.class deleted file mode 100644 index 1a86bdc..0000000 --- a/examples/calc.class +++ /dev/null @@ -1,438 +0,0 @@ - '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 - ) - ); -} diff --git a/examples/calc.lime b/examples/calc.lime deleted file mode 100644 index 4b75dc5..0000000 --- a/examples/calc.lime +++ /dev/null @@ -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/$ ')' -. diff --git a/examples/calc/calc.class b/examples/calc/calc.class new file mode 100644 index 0000000..e0001d7 --- /dev/null +++ b/examples/calc/calc.class @@ -0,0 +1,664 @@ + '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 diff --git a/examples/calc/calc.lime b/examples/calc/calc.lime new file mode 100644 index 0000000..5fb88fb --- /dev/null +++ b/examples/calc/calc.lime @@ -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; + } +. diff --git a/examples/calc.php b/examples/calc/calc.php similarity index 90% rename from examples/calc.php rename to examples/calc/calc.php index fbed885..0f2c06a 100644 --- a/examples/calc.php +++ b/examples/calc/calc.php @@ -6,10 +6,12 @@ and use it in another calculation like: '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 diff --git a/examples/error/error.lime b/examples/error/error.lime new file mode 100644 index 0000000..f3a48c0 --- /dev/null +++ b/examples/error/error.lime @@ -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); + } +; diff --git a/examples/error/error.php b/examples/error/error.php new file mode 100644 index 0000000..e80ce13 --- /dev/null +++ b/examples/error/error.php @@ -0,0 +1,29 @@ +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); diff --git a/lime.php b/lime.php index 6adb559..1fbf7cb 100755 --- a/lime.php +++ b/lime.php @@ -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) { diff --git a/parse_engine.php b/parse_engine.php index 1fd108c..ceadea3 100644 --- a/parse_engine.php +++ b/parse_engine.php @@ -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
\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); }