The real problem is deciding where the colour ends, since you want two word colours. (You mentioned 'burnt umber' as possibly being a valid colour.) What follows is a grammar that allows colours to be quoted. It's good practive to seperate token rules from the grammar rules.
-- grammar: # grammar: order: quantity color item quantity: number color: id | qstring item: id # tokens: number: /\d+/ id: /[a-zA-Z][-_a-zA-Z0-9]*/ qstring: /"(?:\\["\\]|[^"\\])*"/ { $return = unquote($item[1]); } | /'(?:\\['\\]|[^'\\])*'/ { $return = unquote($item[1]); } -- helper (non-grammar) code: sub unquote { local $_ = $_[0]; s/^['"]//; s/['"]$//; s/\\(.)/\1/g; return $_; } --
Checking whether the colour is legit or not is usually done after the parsing is done, or at least, when the tokenizing is done. That allows you to find multiple errors while running the compiler only once. For example, if you've read Larry Walls's Apocolypses, you may have noticed he makes a few allusions to items that shouldn't be verified by the parser for just this reason. What follows is a piece of code that introduces validation of colours:
-- helper (non-grammar) code: my @COLORS = ( 'red' 'green' 'blue' 'cyan' 'magenta' 'burnt umber' ); my %COLORS; { my $idx = 0; %COLORS = map { $_ => $idx++ } @COLORS; } sub unquote { local $_ = $_[0]; s/^['"]//; s/['"]$//; s/\\(.)/\1/g; return $_; } my $error = 0; ... parse ... die("Validation errors were found.\n") if ($error); -- grammar: # grammar: order: quantity color item quantity: number color: id | qstring { $return = $COLORS{$item[1]}; # Uncomment the following if you want # to have multiple errors listed. # unless (defined($return)) # { # warn("Line $thisline: Invalid color.\n"); # $error = 1; # $return = undef; # } # 1; } item: id { ($return) = $item[1] =~ /^(pen|pencil)$/; # Uncomment the following if you want # to have multiple errors listed. # unless (defined($return)) # { # warn("Line $thisline: Invalid item.\n"); # $error = 1; # $return = undef; # } # 1; } # tokens: number: /\d+/ id: /[a-zA-Z][-_a-zA-Z0-9]*/ qstring: /"(?:\\["\\]|[^"\\])*"/ { $return = unquote($item[1]); } | /'(?:\\['\\]|[^'\\])*'/ { $return = unquote($item[1]); } --
In reply to Re: Dynamic expansion of tokens with Parse::RecDescent
by ikegami
in thread Dynamic expansion of tokens with Parse::RecDescent
by jaldhar
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |