Added support for inline %prec definitions

master
Richard van Velzen 2011-12-29 02:04:17 +01:00
parent 175b67c614
commit 6c257fc45b
7 changed files with 367 additions and 347 deletions

View File

@ -1,335 +1,315 @@
<?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.
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.
*/
* If you ignore this warning, you're shooting yourself in the brain,
* not the foot.
*/
class calc extends lime_parser {
var $qi = 0;
var $i = array (
0 =>
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
)
);
}

View File

@ -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/$ ')'
.

View File

@ -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

View File

@ -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();

Binary file not shown.

View File

@ -63,6 +63,9 @@ BLOCKCMT "/*"({CC}|{CX})*{CT}
{BLOCKCMT} {}
"/"{WORD}+ |
"/$" out("lambda", yytext+1);
"%prec" {
tok("prec");
}
"%"{WORD}+ {
out("pragma", yytext+1);
yy_push_state(pragma);

View File

@ -260,6 +260,18 @@ class parse_engine {
return explode(' ', $row[$type]);
}
private function get_steps() {
$out = array();
foreach($this->current_row() 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: