2010-02-27 49 views
1

根据WayneH的语法如何使用ANTLR

在此编辑的显示在一个句子中的所有代词和他们的人就是我在我的语法文件。

grammar pfinder; 

options { 
    language = Java; 
} 
sentence 
    : ((words | pronoun) SPACE)* ((words | pronoun) ('.' | '?')) 
    ; 

words 
    : WORDS {System.out.println($text);}; 

pronoun returns [String value] 
    : sfirst {$value = $sfirst.value; System.out.println($sfirst.text + '(' + $sfirst.value + ')');} 
    | ssecond {$value = $ssecond.value; System.out.println($ssecond.text + '(' + $ssecond.value + ')');} 
    | sthird {$value = $sthird.value; System.out.println($sthird.text + '(' + $sthird.value + ')');} 
    | pfirst {$value = $pfirst.value; System.out.println($pfirst.text + '(' + $pfirst.value + ')');} 
    | psecond {$value = $psecond.value; System.out.println($psecond.text + '(' + $psecond.value + ')');} 
    | pthird{$value = $pthird.value; System.out.println($pthird.text + '(' + $pthird.value + ')');}; 

sfirst returns [String value] : ('i' | 'me' | 'my' | 'mine') {$value = "s1";}; 
ssecond returns [String value] : ('you' | 'your'| 'yours'| 'yourself') {$value = "s2";}; 
sthird returns [String value] : ('he' | 'she' | 'it' | 'his' | 'hers' | 'its' | 'him' | 'her' | 'himself' | 'herself') {$value = "s3";}; 
pfirst returns [String value] : ('we' | 'us' | 'our' | 'ours') {$value = "p1";}; 
psecond returns [String value] : ('yourselves') {$value = "p2";}; 
pthird returns [String value] : ('they'| 'them'| 'their'| 'theirs' | 'themselves') {$value = "p3";}; 

WORDS : LETTER*;// {$channel=HIDDEN;}; 
SPACE : (' ')?; 
fragment LETTER : ('a'..'z' | 'A'..'Z'); 

这里,就是我有一个java测试类

import java.util.Scanner; 
import org.antlr.runtime.*; 
import org.antlr.runtime.tree.*; 
import java.util.List; 

public class test2 { 
    public static void main(String[] args) throws RecognitionException { 
     String s; 
     Scanner input = new Scanner(System.in); 
     System.out.println("Eter a Sentence: "); 
     s=input.nextLine().toLowerCase(); 
     ANTLRStringStream in = new ANTLRStringStream(s); 
     pfinderLexer lexer = new pfinderLexer(in); 
     TokenStream tokenStream = new CommonTokenStream(lexer); 
     pfinderParser parser = new pfinderParser(tokenStream); 
     parser.pronoun(); 
    } 
} 

什么,我需要把测试文件,以便它会显示在一个句子里,所有的代词其各个值(s1,s2,...)?

+0

总结这个问题,我会给你留下一些想法。 'LEXER RULES'每次正确匹配时会创建一个令牌。 “FRAGMENT RULES”不创建令牌。永远。他们被用作写更好的Lexer规则的糖。他们不属于解析器规则。 'PARSER RULES'用于按照特定的顺序(“语法”)对TOKENS进行分组,但是它们会解析为“FLAT”令牌列表。没有亲子关系。 'REWRITE RULES'用于将解析器规则塑造为TREE(“父母>孩子,孩子......”),以便于解释。 – Kivin 2010-02-28 05:44:33

+0

最后,如果您不了解我写的任何内容,欢迎您给我发电子邮件(kivin [at] kivin/dot \ ca)或IM me(aim kivinkujata)。 – Kivin 2010-02-28 05:46:58

+0

在你的java测试类中,用 parser.pronoun();改变行。 至 parser.sentence(); 你应该打印所有单词,并在代词后打印“s#”文字。我没有做任何格式化,所以请随时为它添加代码(在单独的行上打印每个单词)。 祝你好运。 – WayneH 2010-03-06 19:08:40

回答

1

片段不会创建令牌,并将它们放置在解析器规则中不会产生理想的结果。

在我的测试中,由此产生(我想!)所需的结果:

program : 
     PRONOUN+ 
    ; 

PRONOUN : 
     'i' | 'me' | 'my' | 'mine' 
    | 'you' | 'your'| 'yours'| 'yourself' 
    | 'he' | 'she' | 'it' | 'his' | 'hers' | 'its' | 'him' | 'her' | 'himself' | 'herself' 
    | 'we' | 'us' | 'our' | 'ours' 
    | 'yourselves' 
    | 'they'| 'them'| 'their'| 'theirs' | 'themselves' 
    ; 

WS : ' ' { $channel = HIDDEN; }; 

WORD : ('A'..'Z'|'a'..'z')+ { $channel = HIDDEN; }; 

在Antlrworks的样品“我踢你”返回的树形结构:program -> [i, you]

我觉得不得不指出Antlr是用来从句子中剥离代词的矫枉过正。考虑使用正则表达式。这个语法不区分大小写。扩展WORD来消费除了你的PRONOUN的字典(例如puncuation等)以外的所有内容,可能有点乏味。将需要消毒输入。

---编辑:针对第二OP:

  • 我已经改变了原来的语法,使易于解析。新的语法是:

    grammar pfinder; 
    
    options { 
        backtrack=true; 
        output = AST; 
    } 
    
    tokens { 
        PROGRAM; 
    } 
    
    program : 
         (WORD* p+=PRONOUN+ WORD*)* 
         -> ^(PROGRAM $p*) 
        ; 
    
    
    PRONOUN : 
         'i' | 'me' | 'my' | 'mine' 
        | 'you' | 'your'| 'yours'| 'yourself' 
        | 'he' | 'she' | 'it' | 'his' | 'hers' | 'its' | 'him' | 'her' | 'himself' | 'herself' 
        | 'we' | 'us' | 'our' | 'ours' | 'yourselves' 
        | 'they'| 'them'| 'their'| 'theirs' | 'themselves' 
    ; 
    
    WS : ' ' { $channel = HIDDEN; }; 
    
    WORD : ('A'..'Z'|'a'..'z')+; 
    

我会解释的变化:现在需要

  • 回溯解决解析器规则程序。也许有更好的方法来写它不需要回溯,但这是我首先想到的。
  • 想象令牌程序已被定义为组合我们的代词。
  • 将每个匹配的程序添加到Antlr var $ p中,并在虚构规则下重写为AST。
  • 解释器的代码现在可以使用CommonTree收集匹配代词
  • 是用C#(我不知道Java的),但我的意图,你就可以阅读和理解写了下面的它。

    static object[] ReadTokens(string text) 
    { 
        ArrayList results = new ArrayList(); 
        pfinderLexer Lexer = new pfinderLexer(new Antlr.Runtime.ANTLRStringStream(text)); 
        pfinderParser Parser = new pfinderParser(new CommonTokenStream(Lexer)); 
        // syntaxTree is imaginary token {PROGRAM}, 
        // its children are the pronouns collected by $p in grammar. 
        CommonTree syntaxTree = Parser.program().Tree as CommonTree; 
        if (syntaxTree == null) return null; 
        foreach (object pronoun in syntaxTree.Children) 
        { 
         results.Add(pronoun.ToString()); 
        } 
        return results.ToArray(); 
    } 
    
  • 调用ReadTokens( “我踢你和他们”)返回数组[ “我”, “你”, “他们”]

1

如果你正在尝试做一些对口语/书面语言的高级分析,你可能会考虑使用某种自然语言处理工具。例如,TagHelper Tools会告诉你哪些元素是代词(以及动词,名词,副词和其他深奥的语法结构)。(THT是我熟悉的唯一类型的工具,所以不要把它当作特别的赞叹)。

1

我认为您需要了解更多关于ANTLR中的词法分析规则,词法分析器规则以大写字母开头并为分析器将查看的流生成标记。 Lexer片段规则不会为流生成标记,但会帮助其他词法分析器规则生成标记,查看词法分析规则WORDS和LETTER(LETTER不是标记,但确实可帮助WORDS创建标记)。

现在,当文本文字被放入解析器规则(规则名称将以小写字母开头)时,文本文字也是词法分析器将识别并传递的有效标记(至少在您使用ANTLR时 - I没有使用类似于ANTLR的任何其他工具来回答它们)。

我注意到的下一件事是你的''和'代词'规则似乎是同一件事。我评论了's'规则,并将所有内容都放入'代名词'规则中,然后最后一件事是学习如何将操作放入语法中,您在's'规则中有一些设置返回值。我让代词规则返回一个字符串值,这样如果你想在你的'句子'规则中采取行动,你很容易就能完成你的“-i代词”评论/回答。因为我不知道你的确切结果是什么,所以我用你的语法进行了练习,并做了一些细微的修改和重组(把我认为是解析器规则的东西移到顶部,并将所有词法分析规则保留在底部)在一些我认为会向你显示你需要的行动中。此外,可能有几种不同的方式来做到这一点,我不认为我的解决方案是最适合你的任何可能的结果通缉,但这里是一个语法我能得到ANTLRWorks工作:

grammar pfinder; 

options { 
    language = Java; 
} 
sentence 
    : ((words | pronoun) SPACE)* ((words | pronoun) ('.' | '?')) 
    ; 

words 
    : WORDS {System.out.println($text);}; 

pronoun returns [String value] 
    : sfirst {$value = $sfirst.value; System.out.println($sfirst.text + '(' + $sfirst.value + ')');} 
    | ssecond {$value = $ssecond.value; System.out.println($ssecond.text + '(' + $ssecond.value + ')');} 
    | sthird {$value = $sthird.value; System.out.println($sthird.text + '(' + $sthird.value + ')');} 
    | pfirst {$value = $pfirst.value; System.out.println($pfirst.text + '(' + $pfirst.value + ')');} 
    | psecond {$value = $psecond.value; System.out.println($psecond.text + '(' + $psecond.value + ')');} 
    | pthird{$value = $pthird.value; System.out.println($pthird.text + '(' + $pthird.value + ')');}; 

//s returns [String value] 
// : exp=sfirst {$value = "s1";} 
// | exp=ssecond {$value = "s2";} 
// | exp=sthird {$value = "s3";} 
// | exp=pfirst {$value = "p1";} 
// | exp=psecond {$value = "p2";} 
// | exp=pthird {$value = "p3";} 
// ; 

sfirst returns [String value] : ('i' | 'me' | 'my' | 'mine') {$value = "s1";}; 
ssecond returns [String value] : ('you' | 'your'| 'yours'| 'yourself') {$value = "s2";}; 
sthird returns [String value] : ('he' | 'she' | 'it' | 'his' | 'hers' | 'its' | 'him' | 'her' | 'himself' | 'herself') {$value = "s3";}; 
pfirst returns [String value] : ('we' | 'us' | 'our' | 'ours') {$value = "p1";}; 
psecond returns [String value] : ('yourselves') {$value = "p2";}; 
pthird returns [String value] : ('they'| 'them'| 'their'| 'theirs' | 'themselves') {$value = "p3";}; 

WORDS : LETTER*;// {$channel=HIDDEN;}; 
SPACE : (' ')?; 
fragment LETTER : ('a'..'z' | 'A'..'Z'); 

我认为最终的结果就是,这个语法会告诉你如何完成你正在做的事情,无论结果如何,都需要修改。

好运。

我想你只需要在你的测试类中改变一行, parser.pronoun(); 致: parser.sentence();

您可能还想在语法中更改其他一些内容: SPACE:''; 句子:(单词|代词)(SPACE(单词|代词))*('。'|'?'); //那么你可能想在句子和单词/代词之间加一条规则。

+0

谢谢。我不知道可以在antlr中使用java代码。 另一个问题。如果我想展示一切,我能做到吗? ,因为在上面的代码中,当你输入“我踢你”时,它会显示“我(s1)”,所以句子的其他部分被忽略。 是否有一个循环或者它可以显示所有句子,比如它会输出“我(s1)踢你(s2)”或者“我(s1)你(s2)”? – XIII 2010-02-28 04:34:58

+0

如果你只是得到第一个单词,你的控制程序中会有一些东西。当我把“我踢你”,在ANTLRWorks它将显示: 我(s1) 踢 你(s2) 在调试模式下,我不得不一步步完成。你可以用第二个代词 – WayneH 2010-02-28 14:15:54

+0

来代表我的测试程序。我不知道为什么它只显示它找到的第一个代词 – XIII 2010-03-06 13:33:11