Другой ответ относительно вывода Data :: Dumper правильный. Однако ваша грамматика не работает так, как вы ожидаете.
Когда вы анализируете ввод 'foo'
, Марпа рассмотрит три варианта Param
. Предсказанные лексемы в этой позиции:
Unquoted ~ [^\s\/\(\),&:\"~]+
'"'
') Quoted ('
Да, последнее буквально ) Quoted (
, а не что-либо, содержащее одну кавычку.
Даже если бы это было ([']) Quoted (['])
: из-за самого длинного соответствия токена лексема без кавычек будет соответствовать всему вводу, включая одинарную кавычку.
Что будет с входом типа " foo "
(с двойными кавычками)? Теперь только лексема '"'
будет соответствовать, тогда все пробелы будут отброшены, затем лексема в кавычках совпадет, затем все пробелы будут отброшены, а затем закрывается "
.
Чтобы предотвратить такое пропуск пропуска пробелов и предотвратить предпочтение правила Unquoted из-за LATM, имеет смысл описывать строки в кавычках как лексемы. Например:
Param ::= Unquoted | Quoted
Unquoted ~ [^'"]+
Quoted ~ DQ | SQ
DQ ~ '"' DQ_Body '"' DQ_Body ~ [^"]*
SQ ~ ['] SQ_Body ['] SQ_Body ~ [^']*
Эти лексемы будут включать любые кавычки и экранированные символы, поэтому вам нужно постобработать содержимое лексемы. Вы можете сделать это, используя систему событий (которая концептуально чиста, но немного громоздка в реализации), или добавить действие, которое выполняет эту обработку во время анализа разбора.
Поскольку у лексем не может быть действий, обычно лучше добавить прокси-продукт:
Param ::= Unquoted | Quoted
Unquoted ~ [^'"]+
Quoted ::= Quoted_Lexeme action => process_quoted
Quoted_Lexeme ~ DQ | SQ
DQ ~ '"' DQ_Body '"' DQ_Body ~ [^"]*
SQ ~ ['] SQ_Body ['] SQ_Body ~ [^']*
Тогда действие может сделать что-то вроде:
sub process_quoted {
my (undef, $s) = @_;
# remove delimiters from double-quoted string
return $1 if $s =~ /^"(.*)"$/s;
# remove delimiters from single-quoted string
return $1 if $s =~ /^'(.*)'$/s;
die "String was not delimited with single or double quotes";
}