From 6c257fc45ba620d547f6b18f55825a727a022f18 Mon Sep 17 00:00:00 2001 From: Richard van Velzen Date: Thu, 29 Dec 2011 02:04:17 +0100 Subject: [PATCH] Added support for inline %prec definitions --- examples/calc.class | 640 +++++++++++++++++++++----------------------- examples/calc.lime | 2 + lime.bootstrap | 4 + lime.php | 48 ++-- lime_scan_tokens | Bin 22209 -> 22209 bytes lime_scan_tokens.l | 3 + parse_engine.php | 17 +- 7 files changed, 367 insertions(+), 347 deletions(-) diff --git a/examples/calc.class b/examples/calc.class index cb2f3c5..e1e4dd9 100644 --- a/examples/calc.class +++ b/examples/calc.class @@ -1,335 +1,315 @@ - array ( - 'exp' => 's 1', - 'var' => 's 15', - 'num' => 's 3', - '\'(\'' => 's 12', - 'stmt' => 's 18', - '\'start\'' => 'a \'start\'', - ), - 1 => - array ( - '\'+\'' => 's 2', - '\'-\'' => 's 6', - '\'*\'' => 's 8', - '\'/\'' => 's 10', - '#' => 'r 0', - ), - 2 => - array ( - 'num' => 's 3', - 'var' => 's 4', - 'exp' => 's 5', - '\'(\'' => 's 12', - ), - 3 => - array ( - '\'+\'' => 'r 2', - '\'-\'' => 'r 2', - '\'*\'' => 'r 2', - '\'/\'' => 'r 2', - '\')\'' => 'r 2', - '#' => 'r 2', - ), - 4 => - array ( - '\'+\'' => 'r 3', - '\'-\'' => 'r 3', - '\'*\'' => 'r 3', - '\'/\'' => 'r 3', - '\')\'' => 'r 3', - '#' => 'r 3', - ), - 5 => - array ( - '\'+\'' => 'r 4', - '\'-\'' => 'r 4', - '\'*\'' => 's 8', - '\'/\'' => 's 10', - '\')\'' => 'r 4', - '#' => 'r 4', - ), - 6 => - array ( - 'num' => 's 3', - 'var' => 's 4', - 'exp' => 's 7', - '\'(\'' => 's 12', - ), - 7 => - array ( - '\'+\'' => 'r 5', - '\'-\'' => 'r 5', - '\'*\'' => 's 8', - '\'/\'' => 's 10', - '\')\'' => 'r 5', - '#' => 'r 5', - ), - 8 => - array ( - 'num' => 's 3', - 'var' => 's 4', - 'exp' => 's 9', - '\'(\'' => 's 12', - ), - 9 => - array ( - '\'+\'' => 'r 6', - '\'-\'' => 'r 6', - '\'*\'' => 'r 6', - '\'/\'' => 'r 6', - '\')\'' => 'r 6', - '#' => 'r 6', - ), - 10 => - array ( - 'num' => 's 3', - 'var' => 's 4', - 'exp' => 's 11', - '\'(\'' => 's 12', - ), - 11 => - array ( - '\'+\'' => 'r 7', - '\'-\'' => 'r 7', - '\'*\'' => 'r 7', - '\'/\'' => 'r 7', - '\')\'' => 'r 7', - '#' => 'r 7', - ), - 12 => - array ( - 'num' => 's 3', - 'var' => 's 4', - 'exp' => 's 13', - '\'(\'' => 's 12', - ), - 13 => - array ( - '\'+\'' => 's 2', - '\'-\'' => 's 6', - '\'*\'' => 's 8', - '\'/\'' => 's 10', - '\')\'' => 's 14', - ), - 14 => - array ( - '\'/\'' => 'r 8', - '\'*\'' => 'r 8', - '\'-\'' => 'r 8', - '\'+\'' => 'r 8', - '\')\'' => 'r 8', - '#' => 'r 8', - ), - 15 => - array ( - '\'=\'' => 's 16', - '\'+\'' => 'r 3', - '\'-\'' => 'r 3', - '\'*\'' => 'r 3', - '\'/\'' => 'r 3', - '#' => 'r 3', - ), - 16 => - array ( - 'exp' => 's 17', - 'num' => 's 3', - 'var' => 's 4', - '\'(\'' => 's 12', - ), - 17 => - array ( - '\'+\'' => 's 2', - '\'-\'' => 's 6', - '\'*\'' => 's 8', - '\'/\'' => 's 10', - '#' => 'r 1', - ), - 18 => - array ( - '#' => 'r 9', - ), -); -function reduce_0_stmt_1($tokens, &$result) { -# -# (0) stmt := exp -# -$result = reset($tokens); - echo " -> "; echo $tokens[0]; 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); - -} - -function reduce_3_exp_2($tokens, &$result) { -# -# (3) exp := var -# -$result = reset($tokens); - $result = get_variable($tokens[0]); -} - -function reduce_4_exp_3($tokens, &$result) { -# -# (4) exp := exp '+' exp -# -$result = reset($tokens); - $result = $tokens[0] + $tokens[2]; -} - -function reduce_5_exp_4($tokens, &$result) { -# -# (5) exp := exp '-' exp -# -$result = reset($tokens); - $result = $tokens[0] - $tokens[2]; -} - -function reduce_6_exp_5($tokens, &$result) { -# -# (6) exp := exp '*' exp -# -$result = reset($tokens); - $result = $tokens[0] * $tokens[2]; -} - -function reduce_7_exp_6($tokens, &$result) { -# -# (7) exp := exp '/' exp -# -$result = reset($tokens); - $result = $tokens[0] / $tokens[2]; -} - -function reduce_8_exp_7($tokens, &$result) { -# -# (8) exp := '(' exp ')' -# -$result = $tokens[1]; - -} - -function reduce_9_start_1($tokens, &$result) { -# -# (9) 'start' := stmt -# -$result = reset($tokens); - -} - -var $method = array ( - 0 => 'reduce_0_stmt_1', - 1 => 'reduce_1_stmt_2', - 2 => 'reduce_2_exp_1', - 3 => 'reduce_3_exp_2', - 4 => 'reduce_4_exp_3', - 5 => 'reduce_5_exp_4', - 6 => 'reduce_6_exp_5', - 7 => 'reduce_7_exp_6', - 8 => 'reduce_8_exp_7', - 9 => 'reduce_9_start_1', -); -var $a = array ( - 0 => - array ( - 'symbol' => 'stmt', - 'len' => 1, - 'replace' => true, - ), - 1 => - array ( - 'symbol' => 'stmt', - 'len' => 3, - 'replace' => true, - ), - 2 => - array ( - 'symbol' => 'exp', - 'len' => 1, - 'replace' => true, - ), - 3 => - array ( - 'symbol' => 'exp', - 'len' => 1, - 'replace' => true, - ), - 4 => - array ( - 'symbol' => 'exp', - 'len' => 3, - 'replace' => true, - ), - 5 => - array ( - 'symbol' => 'exp', - 'len' => 3, - 'replace' => true, - ), - 6 => - array ( - 'symbol' => 'exp', - 'len' => 3, - 'replace' => true, - ), - 7 => - array ( - 'symbol' => 'exp', - 'len' => 3, - 'replace' => true, - ), - 8 => - array ( - 'symbol' => 'exp', - 'len' => 3, - 'replace' => true, - ), - 9 => - array ( - 'symbol' => '\'start\'', - 'len' => 1, - 'replace' => true, - ), -); + public $qi = 0; + public $i = array( + array( + 'exp' => 's 1', + 'var' => 's 17', + 'num' => 's 3', + "'('" => 's 14', + 'stmt' => 's 20', + "'start'" => "a 'start'" + ), + array( + "'+'" => 's 2', + "'-'" => 's 6', + "'*'" => 's 8', + "'/'" => 's 10', + "'^'" => 's 12', + '#' => 'r 0' + ), + array( + 'num' => 's 3', + 'var' => 's 4', + 'exp' => 's 5', + "'('" => 's 14' + ), + array( + "'+'" => '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' + ), + array( + "'+'" => 'r 4', + "'-'" => 'r 4', + "'*'" => 's 8', + "'/'" => 's 10', + "'^'" => 's 12', + "')'" => 'r 4', + '#' => 'r 4' + ), + array( + 'num' => 's 3', + 'var' => 's 4', + 'exp' => 's 7', + "'('" => 's 14' + ), + array( + "'+'" => 'r 5', + "'-'" => 'r 5', + "'*'" => 's 8', + "'/'" => 's 10', + "'^'" => 's 12', + "')'" => 'r 5', + '#' => 'r 5' + ), + array( + 'num' => 's 3', + 'var' => 's 4', + 'exp' => 's 9', + "'('" => 's 14' + ), + array( + "'+'" => 'r 6', + "'-'" => 'r 6', + "'*'" => 'r 6', + "'/'" => 'r 6', + "'^'" => 's 12', + "')'" => 'r 6', + '#' => 'r 6' + ), + array( + 'num' => 's 3', + 'var' => 's 4', + 'exp' => 's 11', + "'('" => 's 14' + ), + array( + "'+'" => 'r 7', + "'-'" => 'r 7', + "'*'" => 'r 7', + "'/'" => 'r 7', + "'^'" => 's 12', + "')'" => 'r 7', + '#' => 'r 7' + ), + array( + 'num' => 's 3', + 'var' => 's 4', + 'exp' => 's 13', + "'('" => 's 14' + ), + array( + "'+'" => 'r 8', + "'-'" => 'r 8', + "'*'" => 'r 8', + "'/'" => 'r 8', + "'^'" => 's 12', + "')'" => 'r 8', + '#' => 'r 8' + ), + array( + 'num' => 's 3', + 'var' => 's 4', + 'exp' => 's 15', + "'('" => 's 14' + ), + array( + "'+'" => 's 2', + "'-'" => 's 6', + "'*'" => 's 8', + "'/'" => 's 10', + "'^'" => 's 12', + "')'" => 's 16' + ), + array( + "'^'" => 'r 9', + "'/'" => 'r 9', + "'*'" => 'r 9', + "'-'" => 'r 9', + "'+'" => 'r 9', + "')'" => 'r 9', + '#' => 'r 9' + ), + array( + "'='" => 's 18', + "'+'" => 'r 3', + "'-'" => 'r 3', + "'*'" => 'r 3', + "'/'" => 'r 3', + "'^'" => 'r 3', + '#' => 'r 3' + ), + array( + 'exp' => 's 19', + 'num' => 's 3', + 'var' => 's 4', + "'('" => 's 14' + ), + array( + "'+'" => 's 2', + "'-'" => 's 6', + "'*'" => 's 8', + "'/'" => 's 10', + "'^'" => 's 12', + '#' => 'r 1' + ), + array( + '#' => 'r 10' + ) + ); + function reduce_0_stmt_1($tokens, &$result) { + // (0) stmt := exp + $result = reset($tokens); + echo " -> "; echo $tokens[0]; 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); + } + + function reduce_3_exp_2($tokens, &$result) { + // (3) exp := var + $result = reset($tokens); + $result = get_variable($tokens[0]); + } + + function reduce_4_exp_3($tokens, &$result) { + // (4) exp := exp '+' exp + $result = reset($tokens); + $result = $tokens[0] + $tokens[2]; + } + + function reduce_5_exp_4($tokens, &$result) { + // (5) exp := exp '-' exp + $result = reset($tokens); + $result = $tokens[0] - $tokens[2]; + } + + function reduce_6_exp_5($tokens, &$result) { + // (6) exp := exp '*' exp + $result = reset($tokens); + $result = $tokens[0] * $tokens[2]; + } + + function reduce_7_exp_6($tokens, &$result) { + // (7) exp := exp '/' exp + $result = reset($tokens); + $result = $tokens[0] / $tokens[2]; + } + + function reduce_8_exp_7($tokens, &$result) { + // (8) exp := exp '^' exp + $result = reset($tokens); + $result = pow($tokens[0], $tokens[2]); + } + + function reduce_9_exp_8($tokens, &$result) { + // (9) exp := '(' exp ')' + $result = $tokens[1]; + } + + function reduce_10_start_1($tokens, &$result) { + // (10) '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_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' => "'start'", + 'len' => 1, + 'replace' => true + ) + ); } diff --git a/examples/calc.lime b/examples/calc.lime index d55deb1..984c4ad 100644 --- a/examples/calc.lime +++ b/examples/calc.lime @@ -3,6 +3,7 @@ %left '+' '-' %left '*' '/' +%right '^' stmt = exp { echo " -> "; echo $1; echo "\n"; } | var/v '=' exp/e { @@ -18,6 +19,7 @@ exp = num | exp '-' exp { $$ = $1 - $3; } | exp '*' exp { $$ = $1 * $3; } | exp '/' exp { $$ = $1 / $3; } +| exp '^' exp { $$ = pow($1, $3); } | '(' exp/$ ')' . diff --git a/lime.bootstrap b/lime.bootstrap index 63791c7..1730b64 100644 --- a/lime.bootstrap +++ b/lime.bootstrap @@ -22,6 +22,7 @@ lit : $$ = new lime_glyph($1, NULL); to slot : $$ = new lime_rhs(); rhs slot : $$->add($2); +rhs prec tok : $$->set_prec_glyph($3); to rhs '{' code '}' : $$ = $2; to action @@ -29,3 +30,6 @@ to action code php : $$.=$2; code '{' code '}' : $$.='{'.$3.'}'; to code +sym : +lit : +to tok diff --git a/lime.php b/lime.php index 7f9eb6f..085023f 100755 --- a/lime.php +++ b/lime.php @@ -160,11 +160,13 @@ class error extends step { class shift extends step { public $q; + public $rule; - public function __construct(sym $sym, $q) { + public function __construct(sym $sym, $q, rule $rule) { parent::__construct($sym); $this->q = $q; + $this->rule = $rule; } public function instruction() { @@ -178,7 +180,7 @@ class shift extends step { bug_unless($that instanceof reduce); // That being said, the resolution is a matter of precedence. - $shift_prec = $this->sym->right_prec; + $shift_prec = $this->rule->right_prec; $reduce_prec = $that->rule->prec; // If we don't have defined precedence levels for both options, @@ -274,8 +276,8 @@ class state { } } - public function add_shift(sym $sym, $state) { - $this->add_instruction(new shift($sym, $state->id)); + public function add_shift(sym $sym, $state, $rule) { + $this->add_instruction(new shift($sym, $state->id, $rule)); } public function add_reduce(sym $sym, $rule) { @@ -375,7 +377,7 @@ class sym { } class rule { - public function __construct($id, $sym, $rhs, $code, $look, $replace) { + public function __construct($id, $sym, $rhs, $code, $look, $replace, $prec_sym) { bug_unless(is_int($look)); $this->id = $id; @@ -384,8 +386,9 @@ class rule { $this->code = $code; $this->look = $look; $this->replace = $replace; - //$this->prec_sym = $prec_sym; + $this->prec_sym = $prec_sym; $this->prec = 0; + $this->right_prec = 0; $this->first = array(); $this->epsilon = count($rhs); } @@ -401,15 +404,17 @@ class rule { // is a reasonable alternative behaviour, but I don't see the big // deal just now. - //$prec_sym = $this->prec_sym; - //if (!$prec_sym) - $prec_sym = $this->rightmost_terminal(); + $prec_sym = $this->prec_sym; + if (!$prec_sym) { + $prec_sym = $this->rightmost_terminal(); + } if (!$prec_sym) { return; } $this->prec = $prec_sym->left_prec; + $this->right_prec = $prec_sym->right_prec; } private function rightmost_terminal() { @@ -664,7 +669,7 @@ class lime { return "'{$real}'" . count($this->rule); } - function add_raw_rule($lhs, $rhs, $code, $look, $replace) { + function add_raw_rule($lhs, $rhs, $code, $look, $replace, $prec_sym) { $sym = $this->sym($lhs); $sym->term = false; @@ -679,7 +684,7 @@ class lime { } $rid = count($this->rule); - $r = new rule($rid, $sym, $rs, $code, $look, $replace); + $r = new rule($rid, $sym, $rs, $code, $look, $replace, $prec_sym); $this->rule[$rid] = $r; $sym->rule[] = $r; } @@ -754,7 +759,7 @@ class lime { $candidate = current($this->start_symbol_set); // Did the person try to set a start symbol at all? - if (!$candidate) { + if (!is_object($candidate)) { return $this->first_rule_lhs(); } @@ -862,7 +867,7 @@ class lime { } $dest = $this->get_state($basis); - $state->add_shift($this->sym($glyph), $dest); + $state->add_shift($this->sym($glyph), $dest, $segment[0]->rule); } } @@ -1074,6 +1079,8 @@ class lime_language_php extends lime_language { } class lime_rhs { + public $prec_glyph; + function __construct() { // Construct and add glyphs and actions in whatever order. // Then, add this to a lime_rewrite. @@ -1083,10 +1090,14 @@ class lime_rhs { $this->rhs = array(); } - function add(lime_slot $slot) { + public function add(lime_slot $slot) { $this->rhs[] = $slot; } + public function set_prec_glyph($glyph) { + $this->prec_glyph = $glyph; + } + function install_rule(lime $lime, $lhs) { // This is the part that has to break the rule into subrules if necessary. $rhs = $this->rhs; @@ -1095,6 +1106,11 @@ class lime_rhs { $rhs[] = new lime_action('', null); } + $prec_sym = null; + if ($this->prec_glyph) { + $prec_sym = $lime->sym($this->prec_glyph); + } + // Now, split it into chunks based on the actions. $lang = $lime->language(); @@ -1118,12 +1134,12 @@ class lime_rhs { // no. $subsymbol = $lime->trump_up_bogus_lhs($lhs); $action = $lang->default_result() . $preamble . $code; - $lime->add_raw_rule($subsymbol, $subrule, $action, $look, false); + $lime->add_raw_rule($subsymbol, $subrule, $action, $look, false, $prec_sym); $subrule = array($subsymbol); } else { // yes. $action = $result_code . $preamble . $code; - $lime->add_raw_rule($lhs, $subrule, $action, $look, true); + $lime->add_raw_rule($lhs, $subrule, $action, $look, true, $prec_sym); } } else { impossible(); diff --git a/lime_scan_tokens b/lime_scan_tokens index 70c7e0c9b2f03af77b11da064f371d9cd451d5c2..bb2b32765071218e3553a851b45389cbaee3cd0b 100755 GIT binary patch delta 4416 zcma)9dstOf7GLLbfOGA_R)!7dDKqaT?vkVsF)>ℜG_P;wffOZP9Kt$ zQ*zXM0N2G3qCN|nVfc$MJS`0V1BSE0ut^wx)DboJ^vFtmr)1BKlHq+pG(IaDKSd)9 zp9n)CU(<(3m)K|6l!T$bUAPm5`2&Wt{K&9v(r3<_!z9U&`h%)E z(poWK-@B|Ba=graCN40<=#Jmyx`1FlVAAs*Ls)nO{H_LK@P09PL?FVI-&ECIeZ_pr zP%Je$&3-RQ(nWsD|4pfsA2a6rxo)UxLua)CedNR3V+_uG@*7n>MdG@e>{<`vp!)yF z)&6b|L_Oz^md9NcgKo_`a9?&g%C(V41x%K9@{)jXDU}}&_)!;im>)AWW4Xfu&R0?;tXa|_mIGuc}mT(UvUt*^L|rIqN7x?=Y+aeJAVqz)JaV|$sD8m{!3nFUITL0oGO*D zGGdW*j_(_BNk?rwYvg^p*fu^qa*J+e8>dA)C_T;xB4$MI$2-_uiJ5j3DE9m)#acYlyiC!#WBK7}4;vfvblJni0b=C zI95g_K6PxAs;aKv@h8^j{MW?eCfA@x{kzJdZr(e3sx6!hBtdjQ19?GZx`RR>p%e@a z1q-AwlqT{gKa@t)h5s-JkplHa9~nJ}@Is*%(QxQM%?STtfC#;;f2RC0-k8;L4a#o2;3|K%P1_ z4R?Go#{W{`D|Fxrrg8KZbM@hh+iXLv@r0wvN`*qf}1Cw2BtOuMGWq zX*sQ?Y8pu!XcO6}fgH4(O#A2nLbM>%5e(8n-F#%U*;a(9ng_W@lOobnktW4df^bC$ zIv?c%NI3>sG}!L(TTDybHsN35t}R8MBJ>hHiUxZvq6+jEy_UHBmQv+(GzxPSj3sn0 zMDS%0!It5PJcIluibvs`*wN)d$S)zm$WoD?VKfF3?k>#~N9i<{##1s)MBKY51LX+J z(|~6R>>kf_cuu8Uno0ST0>2DyiH)^I(SStLDEJDWWJoSNXA2+HQjiR@P^KVdZ%G8* zk{Ec!Xfh5x$7vFedOX%P0qdGb1<+h*(hy0t!6j9bG`b~|XgW>OWHL>rEXsrq$TZZa zX)=TIXoe2H%&qR2^5QovQU}@g$3{SZ?479TRAK)ffM5t zo*5UIJsdM!f_Fa@FGxHz9HkdT><%)lNhrmN$#}dBJg%7ATv!Fm5I(#+&dN=3{!&>lG-Dld5}GR(F}e<9o zV3(Dn(9=-CKLiT>2I{+ARuZApp+!*9z8YwQ?t(rCeHH42c0f--{|fyWdIf5A$V$*J z=mS;N&Ws7cI@{%Qs`@-O?2G4BwG)`|cU8R(Ec;AVN9l;dK3COz;2B^wa2&o)uK=z1 zQoajp1G<2Ze4(lecIc0RV}a%P?9K$f2V4$ZbVj0K z2!Kz+oPGoVJ_*bRj>DN@CGd0LF5uW}s@ew30rmhN2KEDg4>aKO(f}L}+zHGFJ_}q4 zd>Oa{*amC`b^t%{w&4y@>4)JQ(17pIXTb5mW&cJ1p#C}n07n3K0Mmi3z*)c#fQx|r zz!spvm#7Ok9{33`9~kvD`UCd>4+8fBj|0VbllV-MS(?gMk|L7=dR28k?t`-Zl?Gjo zpLcP+_mlEgFRyy9Vcpp$vrlCkWcft)9pmA$7Mj6#B_~J|ctvuY?!-TNZ}J$afIDE? z%wHv2aD4SkiL`cN+1`QkU{Kv#ClJQ{t=xuXzL)2vSgfyIQq|43d2JZN@H&7b6H_f8^!NuRC zMdYE#T#E83 zu0gq-8#64rwmxppm=tyyIg5LDUjZm5W7Yo#o9r}Ae9?!4vc^gqol~+ZWT}-8OtW}z z#J}D~?wS^-)BE$aX%XH7|B0sDNT0;l@m?o8C*^*mlQwej3`?MB6Op~J--s*mb?5XM zcS~q(m}!xUxMil(_7dz84s2yuliHWzkGvOrvEcX@tkl}?0~aUy(;8n1F8%^M{84am zfd2?6`fmV=Uq=tG1Fys%(sHf;KJeo`GGCZgU<>|(teC)cIP?w2Y((sn6>+K+T&(~3 z1F|9x_JXH_Km7uBFO5$F*F7UE-5M_kKLIWdS;GGz@Q<;>#o#p%d=vOJ^iR;*cj)k? zsbN{E(r#c69M12Nm2WkN=fKzPmz9?_{wnx61PIr7JNQ$4Wp-iJD*S?vgf$Su_+k55 zyjND<(YO^{{HMd&-JS$K5B}nSDg4vG|J*1mJ2jpKo&$eS3e@>g8F&&m&asK5&9_MF zI4wWHbh>HaK1757EZkPE$TlpF&tb_ zX#MtiS;^GeuApr(B8c<1@Vy3}%nbz=X(YE4B;XzCMg1ARQIKHu#S_fd{Ptmjy)jP@ zYy2R159iHIkSe%l?oR6sj4w|4B4#k4iuwCIdY&Xa{Vef|sQ-jUV- delta 4271 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 as $type => $row) { + list($opcode) = explode(' ', $row, 2); + if ($opcode != 'e') { + $out[] = $type; + } + } + + return $out; + } + private function has_step_for($type) { $row = $this->current_row(); return isset($row[$type]); @@ -300,6 +312,9 @@ class parse_engine { // flutter while the parse engine waits for an edible token. // 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); if ($this->has_step_for($type)) { @@ -307,7 +322,7 @@ class parse_engine { } } else { // If that didn't work, give up: - throw new parse_error("Parse Error: ({$type})({$semantic}) not expected"); + throw new parse_error("Parse Error: ({$type})({$semantic}) not expected, expected {" . implode(', ', $expected) . '}'); } break; default: