2011-01-15 2 views
4

У меня есть следующие входныеИспользование Анализировать :: RecDescent

@Book{press, 
    author = "Press, W. and Teutolsky, S. and Vetterling, W. and Flannery B.", 
    title  = "Numerical {R}ecipes in {C}: The {A}rt of {S}cientific {C}omputing", 
    year  = 2007, 
    publisher = "Cambridge University Press" 
} 

, и я должен написать грамматику для генератора синтаксических анализаторов RecDescent. Данные на выходе должны быть изменены для структуры XML и должен выглядеть следующим образом:

<book> 
    <keyword>press</keyword> 
    <author>Press, W.+Teutolsky, S.+Vetterling, W.+Flannery B.</author> 
    <title>Numerical {R}ecipes in {C}: The {A}rt of {S}cientific {C}omputing</title> 

    <year>2007</year> 
    <publisher>Cambridge University Press</publisher> 
</book> 

Дополнительные и повторные поля должны быть представлены в виде ошибок (соответствующее сообщение с номером строки и без дальнейшего разбора). Я попытался начать с примерно так:

use Parse::RecDescent; 

open(my $in, "<", "parsing.txt") or die "Can't open parsing.txt: $!"; 

my $text; 
while (<$in>) { 
    $text .= $_; 
} 

print $text; 

my $grammar = q { 
    beginning: "\@Book\{" keyword fields "\}"   { print "<book>\n",$item[2],$item[3],"</book>"; } 
    keyword: /[a-zA-Z]+/ ","       { return " <keyword>".$item[1]."</keyword>\n"; } 
    fields: one "," two "," tree "," four    { return $item[1].$item[3].$item[5].$item[7]; } 
    one: "author" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" { $item[4] =~ s/\sand\s/\+/g; 
                  return " <author>",$item[4],"</author>\n"; } 
    two: "title" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" { $item[4] =~ s/\sand\s/\+/g; 
                  return " <title>",$item[4],"</title>\n"; } 
    three: "year" "=" /[0-2][0-9][0-9][0-9]/   { return " <year>",$item[3],"</year>\n"; } 
    four: "publisher" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" 
                 { $item[4] =~ s/\sand\s/\+/g; 
                  return " <publisher>",$item[4],"</publisher>\n"; } 
}; 

my $parser = new Parse::RecDescent($grammar) or die ("Bad grammar!"); 
defined $parser->beginning($text) or die ("Bad text!"); 

Но я даже не знаю, правильно ли это сделать. Пожалуйста помоги.

Есть еще одна крошечная проблема. Теги на входе могут быть не в том конкретном порядке, но каждый тег может появляться только один раз. Должен ли я писать субрулы для всех перестановок (автор, название, год, издатель)? Потому что я придумал:

fields: field "," field "," field "," field 
field: one | two | three | four 

но он, очевидно, не мешает повторять теги.

+2

Похоже, вы на хороший старт. Какая у вас проблема? – cam

+1

Существует ограничение на то, какую работу вы должны просить грамматику. не пытайтесь принуждать вас к безрецепции в вашей грамматике; это то, с чем вы можете иметь дело, как только вы проанализировали его в подходящей структуре данных. Поэтому вместо перехода от BibTeX к XML, проанализируйте промежуточную структуру, выполните вычисления по структуре, а затем выведите на XML впоследствии. –

ответ

9

Во-первых, у вас есть опечатка: tree вместо three.

Я побежал программу, но добавил строки:

use strict; 
use warnings; # you should always have strict and warnings on 
$::RD_HINT = 1; # Parse::RecDescent hints 
$::RD_TRACE = 1; # Parse::RecDescent trace 

и получил этот отладочный вывод:

1|beginning |>>Matched terminal<< (return value: | 
    |   |[@Book{])        | 
1|beginning |          |"press,\n author = "Press, 
    |   |          |W. and Teutolsky, S. and 
    |   |          |Vetterling, W. and Flannery 
    |   |          |B.",\n title = "Numerical 
    |   |          |{R}ecipes in {C}: The {A}rt 
    |   |          |of {S}cientific 
    |   |          |{C}omputing",\n year = 
    |   |          |2007,\n publisher = 
    |   |          |"Cambridge University 
    |   |          |Press"\n}\n" 
1|beginning |Trying subrule: [keyword]    | 
2| keyword |Trying rule: [keyword]    | 
2| keyword |Trying production: [/[a-zA-Z]+/ ','] | 
2| keyword |Trying terminal: [/[a-zA-Z]+/]  | 
2| keyword |>>Matched terminal<< (return value: | 
    |   |[press])        | 
2| keyword |          |",\n author = "Press, W. and 
    |   |          |Teutolsky, S. and 
    |   |          |Vetterling, W. and Flannery 
    |   |          |B.",\n title = "Numerical 
    |   |          |{R}ecipes in {C}: The {A}rt 
    |   |          |of {S}cientific 
    |   |          |{C}omputing",\n year = 
    |   |          |2007,\n publisher = 
    |   |          |"Cambridge University 
    |   |          |Press"\n}\n" 
2| keyword |Trying terminal: [',']    | 
2| keyword |>>Matched terminal<< (return value: | 
    |   |[,])         | 
2| keyword |          |"\n author = "Press, W. and 
    |   |          |Teutolsky, S. and 
    |   |          |Vetterling, W. and Flannery 
    |   |          |B.",\n title = "Numerical 
    |   |          |{R}ecipes in {C}: The {A}rt 
    |   |          |of {S}cientific 
    |   |          |{C}omputing",\n year = 
    |   |          |2007,\n publisher = 
    |   |          |"Cambridge University 
    |   |          |Press"\n}\n" 
2| keyword |Trying action       | 
1|beginning |>>Matched subrule: [keyword]<< (return| 
    |   |value: [ <keyword>press</keyword> ]| 
1|beginning |          |"press,\n author = "Press, 
    |   |          |W. and Teutolsky, S. and 
    |   |          |Vetterling, W. and Flannery 
    |   |          |B.",\n title = "Numerical 
    |   |          |{R}ecipes in {C}: The {A}rt 
    |   |          |of {S}cientific 
    |   |          |{C}omputing",\n year = 
    |   |          |2007,\n publisher = 
    |   |          |"Cambridge University 
    |   |          |Press"\n}\n" 
1|beginning |Trying subrule: [fields]    | 
2| fields |Trying rule: [fields]     | 
2| fields |Trying production: [one ',' two ',' | 
    |   |three ',' four]      | 
2| fields |Trying subrule: [one]     | 
3| one |Trying rule: [one]     | 
3| one |Trying production: ['author' '=' '\"' | 
    |   |/[a-zA-Z\s\.\,{}\:]+/ '\"']   | 
3| one |Trying terminal: ['author']   | 
3| one |<<Didn't match terminal>>    | 
3| one |<<Didn't match rule>>     | 
2| fields |<<Didn't match subrule: [one]>>  | 
2| fields |<<Didn't match rule>>     | 
1|beginning |<<Didn't match subrule: [fields]>> | 
1|beginning |<<Didn't match rule>>     | 
Bad text! at parser.pl line 32, <$in> line 6. 

Это показывает, что это застрять в подпункт правила one, и что press, становится положить обратно на входной поток. Это связано с тем, что вы используете return, а не $return = в качестве руководства Parse :: RecDescent says you should.

Кроме того, как только вы назначаете переменную $return, вы больше не можете возвращать список и должны конкатенировать строки вместе вручную.

Вот конечный результат:

use strict; 
use warnings; 
use Parse::RecDescent; 

open(my $in, "<", "parsing.txt") or die "Can't open parsing.txt: $!"; 

my $text; 
while (<$in>) { 
    $text .= $_; 
} 

print $text; 

my $grammar = q { 
    beginning: "\@Book\{" keyword fields /\s*\}\s*/   { print "<book>\n",$item[2],$item[3],"</book>"; } 
    keyword: /[a-zA-Z]+/ ","       { $return = " <keyword>$item[1]</keyword>\n"; } 
    fields: one /,\s*/ two /,\s*/ three /,\s*/ four    { $return = $item[1].$item[3].$item[5].$item[7]; } 
    one: "author" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" { $item[4] =~ s/\sand\s/\+/g; 
                  $return = " <author>$item[4]</author>\n"; } 
    two: "title" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" { $item[4] =~ s/\sand\s/\+/g; 
                  $return = " <title>$item[4]</title>\n"; } 
    three: "year" "=" /[0-2][0-9][0-9][0-9]/   { $return = " <year>$item[3]</year>\n"; } 
    four: "publisher" "=" "\"" /[a-zA-Z\s\.\,\{\}\:]+/ "\"" 
                 { $item[4] =~ s/\sand\s/\+/g; 
                  $return = " <publisher>$item[4]</publisher>\n"; } 
}; 

my $parser = new Parse::RecDescent($grammar) or die ("Bad grammar!"); 
defined $parser->beginning($text) or die ("Bad text!"); 
+0

«$ return =» вместо «return» очень помог. – marooou