label opcode operand operand ... operandwhere the label is optional. So far i have implemented all 'opcodes' except 'IF', and that is what is giving me trouble. But first, let me explain the code.
My idea is to parse each line and add a sub reference (plus the args to the sub via an array ref) to some global array. After the parsing has completed, i then run a loop over that array and call each element as a subroutine. The reason for using two passes is to be able to implement a 'GOTO' command. The 'robot command language' also branches when an 'IF' command is encountered.
Back to the problem. My grammar works except in this one example case:IF int_or_var relop int_or_var label_namewhen P::RD sees that the first 'int_or_var' is a 'var' and not an 'int', it mistakes 'IF' for a label. In other words, the first line below matches correctly to 'IF', but the second matches "incorrectly" to 'label':
IF 9 > 8 L1 # matches IF IF rmove < 8 L1 # matches labelMy question is, how do i specify my grammar to get the second line above to match to 'label' and not 'if'? Here is my code, it should run without any errors and it's display should be self-explanatory. Also, any suggestions or improvements are very welcome. Thanks in advance. :)
use strict; use warnings; use Data::Dumper; use Parse::RecDescent; $RD_HINT = 1; use vars qw( %item @item $return %symbol %axis @code $curr %label ); @axis{'X','Y','Z'} = (0,0,1); @code = (); my $parser = Parse::RecDescent->new(q( startrule : opcode | label opcode label: /[a-z]\w*/i { print "got label: $item[1]\n"; $main::label{$item[1]} = $#main::code; } opcode: IF | YMOVE | XMOVE | DOWN | UP | PRINTLOC | GOTO | SET | ADD | SUB | HALT YMOVE: /YMOVE/i int_or_var { push @main::code, [ sub { $main::axis{Y} += $_[0] }, [$item{int_or_var}], ]; } XMOVE: /XMOVE/i int_or_var { push @main::code, [ sub { $main::axis{X} += $_[0] }, [$item{int_or_var}], ]; } DOWN: /DOWN/i { push @main::code, [ sub { $main::axis{Z}-- },[]]; } UP: /UP/i { push @main::code, [ sub { $main::axis{Z}++ },[]]; } PRINTLOC: /PRINTLOC/i { push @main::code, [ sub { print "@{[map $main::axis{$_},sort keys %main::axis]}\n +" }, [], ]; } IF: /IF/i int_or_var relop int_or_var label_name { print "got if: @item\n"; } GOTO: /GOTO/i label_name { push @main::code, [ sub { $main::curr = $main::label{$item{label_name}} },[] ]; } SET: /SET/i var_name int_or_var { $main::symbol{$item{var_name}} = $item{int_or_var}; push @main::code, [ sub { $main::symbol{$_[0]} = $_[1] }, [$item{var_name}, $item{int_or_var}], ]; } ADD: /ADD/i var_name int_or_var { $main::symbol{$item{var_name}} += $item{int_or_var}; push @main::code, [ sub { $main::symbol{$_[0]} += $_[1] }, [$item{var_name}, $item{int_or_var}], ]; } SUB: /SUB/i var_name int_or_var { $main::symbol{$item{var_name}} -= $item{int_or_var}; push @main::code, [ sub { $main::symbol{$_[0]} -= $_[1] }, [$item{var_name}, $item{int_or_var}], ]; } HALT: /HALT/i { push @main::code, [ sub { exit(0); },[]]; } label_name: /[a-z]\w*/i int_or_var: var_value | int var_name: /[a-z]\w*/i var_value: /[a-z]\w*/i { $return = $main::symbol{$item[1]}; } int: /-*\d+/ relop: '<' | '>' | '==' | '!=' | '>=' | '<=' )); $parser->startrule($_) while <DATA>; for ($curr = 0; $curr < @code; $curr++) { my ($sub,$args) = @{$code[$curr]}; $sub->(@$args); } __DATA__ YMOVE 10 # along y-axis SET RMOVE 0 # sets RMOVE to 0 L1 ADD RMOVE 1 # adds 1 to RMOVE xmove 1 # along x-axis IF rmove < 8 L1 IF 9 < 8 L1 YMOVE -3 down # along z-axis (lower gripper) PRINTLOC HALT
jeffa
L-LL-L--L-LL-L--L-LL-L-- -R--R-RR-R--R-RR-R--R-RR B--B--B--B--B--B--B--B-- H---H---H---H---H---H--- (the triplet paradiddle with high-hat)
In reply to Help with tweaking Parse::RecDescent grammar by jeffa
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |