2012-10-23 24 views
0

我想獲得最簡單的可能的解析器使用JParsec 2.0.1,但我沒有運氣。我有以下AST類:JParsec墮落在簡單的測試

public abstract class Node { 
} 

public final class ConstantNode extends Node { 
    private final String value; 

    public ConstantNode(String value) { 
     this.value = value; 
    } 

    @Override 
    public String toString() { 
     return this.value; 
    } 
} 

和下面的測試代碼:

import junit.framework.Assert; 

import org.codehaus.jparsec.Parser; 
import org.codehaus.jparsec.Parsers; 
import org.codehaus.jparsec.Scanners; 
import org.codehaus.jparsec.Terminals; 
import org.codehaus.jparsec.Token; 
import org.codehaus.jparsec.functors.Map; 
import org.junit.Test; 

import ast.ConstantNode; 
import ast.Node; 

public class ParserTest { 
    private static final Parser<Token> CONSTANT_LEXER = Parsers 
     .or(Terminals.StringLiteral.SINGLE_QUOTE_TOKENIZER, 
      Terminals.StringLiteral.DOUBLE_QUOTE_TOKENIZER) 
     .token(); 

    private static final Parser<Node> CONSTANT_PARSER = CONSTANT_LEXER.map(new Map<Token, Node>() { 
     @Override 
     public Node map(Token from) { 
      return new ConstantNode(from.toString()); 
     } 
    }); 

    private static final Parser<Void> IGNORED = Scanners.WHITESPACES; 

    @Test 
    public void testParser() { 
     Object result = null; 

     // this passes 
     result = CONSTANT_LEXER.parse("'test'"); 
     Assert.assertEquals("test org.codehaus.jparsec.Token", result + " " + result.getClass().getName()); 

     // this fails with exception: org.codehaus.jparsec.error.ParserException: Cannot scan characters on tokens. 
     result = CONSTANT_PARSER.from(CONSTANT_LEXER, IGNORED).parse("'test'"); 
     Assert.assertEquals("test ast.ConstantNode", result + " " + result.getClass().getName()); 
    } 
} 

即使我的詞法被成功解析輸入令牌字符串,我的解析器是無法消耗這些令牌由於JParsec異常。我一遍又一遍地研究了這段代碼,只能假定這是一個jparsec錯誤,或者我誤解了一些明顯的東西。

任何人都可以告訴我我在做什麼錯嗎?

UPDATE:我相信最初的問題是由於遞歸引用。我的CONSTANT_PARSER正在使用CONSTANT_LEXER,然後我再打電話CONSTANT_PARSER.from(CONSTANT_LEXER...)。通過改變我的CONSTANT_PARSER以下內容,我的測試,然後通過:

private static final Parser<Node> CONSTANT_PARSER = Parsers.tokenType(Token.class, "constant").map(new Map<Token, Node>() { 
    @Override 
    public Node map(Token from) { 
     return new ConstantNode(from.toString()); 
    } 
}); 

然而,這仍然還沒有完全按下我。我懷疑有更好的方法可以做到這一點,所以我仍然對任何想法都很感興趣。

回答

0

你在混合2種不同的「解析器」:字符串解析器aka。掃描儀在JParsec和令牌解析器:

CONSTANT_PARSER.from(CONSTANT_LEXER, IGNORED).parse("'test'");

實質上說,CONSTANT_PARSER應該得到它的輸入爲令牌從CONSTANT_LEXER流而忽略作爲分隔符。問題在於CONSTANT_PARSER是由「映射」CONSTANT_LEXER定義的,這意味着它使用詞法分析器解析其輸入,而不是映射結果。這就提出了以下錯誤:

org.codehaus.jparsec.error.ParserException: Cannot scan characters on tokens.

通過定義CONSTANT_PARSER爲Parsers.tokenType(Token.class, "constant")你說有效的解析器使用令牌的流,給它們命名constant。不過,我認爲這不符合你的預期,因爲它可以匹配任何類型的令牌,而不僅僅是常量。

這當然是JParsec中較少記錄的部分之一,但它也沒有很好的記錄!