【问题标题】:Antlr program won't compileAntlr 程序无法编译
【发布时间】:2013-11-28 15:42:23
【问题描述】:

我正在尝试制作一个语法来解析 json 语言

我用来理解每个条目的自动机的链接http://www.json.com

grammar myjson;

prog
    : object+ EOF
    ;

object
    : '{'
        STRING  ':' value 
        (','  STRING  ':' value)*
      '}'
    | '{' EMPTY '}'
    ;

array
    : '[' 
        value 
        (',' value)* 
      ']'
    | '[' EMPTY ']
    ; 

value
    : object | STRING | NUMBER
    | array | BOOL | NULL
    ;

STRING
    : '"' (UNICODE | SPECIAL)* '"'
    ;

UNICODE
    : ~('\u0022' | '\u005C')
    ;

SPECIAL     
    : '\u005C'
      (
      | '"' | '\u005C'  | '\u002F'
      | 'b' | 'f' | 'n' | 'r'
      | 't' | 'u' DIGIT DIGIT DIGIT DIGIT
      )
    ;

NULL: 'null';
BOOL
    : 'true'
    | 'false'
    ;   


NUMBER : ('+'|'-')? DIGIT+ '.' DIGIT* EXPONENT?
       | ('+'|'-')? '.'? DIGIT+ EXPONENT?
       ;

fragment 
EXPONENT : ('e' | 'E') ('+' | '-') ? DIGIT+ 
         ;

fragment
DIGIT  : '0'..'9' 
       ;

fragment
LETTER
    : ('a'..'z' | 'A'..'Z')
    ;

COMM
    : '//' ~('\r'? '\n')   {skip();}    
    | '/*' .* '*/'         {skip();}
    ;

WS
    : ' ' | '\t' | '\r' | '\n' | '\u000c' {skip();} 
    ;

EMPTY
    : ''
    ;   

我想声明我正在使用 antlrworks v 1.4.3,因为这是我的老师建议使用的。

我的问题是这个语法甚至无法编译,因为我收到以下错误

java.util.NoSuchElementException: can't look backwards more than one token in this stream
    at org.antlr.runtime.misc.LookaheadStream.LB(LookaheadStream.java:159)
    at org.antlr.runtime.misc.LookaheadStream.LT(LookaheadStream.java:120)
    at org.antlr.runtime.RecognitionException.extractInformationFromTreeNodeStream(RecognitionException.java:144)
    at org.antlr.runtime.RecognitionException.<init>(RecognitionException.java:111)
    at org.antlr.runtime.MismatchedTreeNodeException.<init>(MismatchedTreeNodeException.java:42)
    at org.antlr.runtime.tree.TreeParser.recoverFromMismatchedToken(TreeParser.java:135)
    at org.antlr.runtime.BaseRecognizer.match(BaseRecognizer.java:115)
    at org.antlr.grammar.v3.TreeToNFAConverter.alternative(TreeToNFAConverter.java:2798)
    at org.antlr.grammar.v3.TreeToNFAConverter.block(TreeToNFAConverter.java:2662)
    at org.antlr.grammar.v3.TreeToNFAConverter.rule(TreeToNFAConverter.java:1995)
    at org.antlr.grammar.v3.TreeToNFAConverter.rules(TreeToNFAConverter.java:1338)
    at org.antlr.grammar.v3.TreeToNFAConverter.grammarSpec(TreeToNFAConverter.java:1288)
    at org.antlr.grammar.v3.TreeToNFAConverter.grammar_(TreeToNFAConverter.java:319)
    at org.antlr.tool.Grammar.buildNFA(Grammar.java:1006)
    at org.antlr.tool.CompositeGrammar.createNFAs(CompositeGrammar.java:390)
    at org.antlr.works.grammar.antlr.ANTLRGrammarEngineImpl.createLexerGrammarFromCombinedGrammar(ANTLRGrammarEngineImpl.java:219)
    at org.antlr.works.grammar.antlr.ANTLRGrammarEngineImpl.createCombinedGrammar(ANTLRGrammarEngineImpl.java:204)
    at org.antlr.works.grammar.antlr.ANTLRGrammarEngineImpl.createGrammars(ANTLRGrammarEngineImpl.java:165)
    at org.antlr.works.grammar.antlr.ANTLRGrammarEngineImpl.analyze(ANTLRGrammarEngineImpl.java:272)
    at org.antlr.works.grammar.engine.GrammarEngineImpl.analyze(GrammarEngineImpl.java:325)
    at org.antlr.works.debugger.local.DBLocal.analyzeGrammar(DBLocal.java:385)
    at org.antlr.works.debugger.local.DBLocal.generateAndCompileGrammar(DBLocal.java:365)
    at org.antlr.works.debugger.local.DBLocal.run(DBLocal.java:222)
    at java.lang.Thread.run(Unknown Source)

我在一篇关于“在这个流中不能向后看多个标记”的帖子中读到词法分析器和解析器语法不匹配的 java 异常,但我不知道那是什么或它指的是什么。我也为没有评论代码而道歉。但是我对antlr了解不多,所以我不想写一些可能会让你失望的东西。

请帮助并提前感谢您

【问题讨论】:

    标签: antlr antlrworks


    【解决方案1】:

    你的语法有几处错误:

    • 从不 匹配(可能)匹配空字符串的标记:您的词法分析器在尝试匹配它们时会进入无限循环。简而言之:删除EMPTY 令牌
    • ' ' | '\t' | '\r' | '\n' | '\u000c' {skip();} 等价于 ' ' | '\t' | '\r' | '\n' | ('\u000c' {skip();})。你想这样做:(' ' | '\t' | '\r' | '\n' | '\u000c') {skip();}
    • 您的SPECIAL 规则匹配单个反斜杠:'\u005C' ( /* NOTHING HERE */ | '"' | ...:删除第一个|'\u005C' ( '"' | ...
    • 否定字符集必须包含单个字符,而不是像您所做的那样包含两个字符:~('\r'? '\n')*(您不能否定 \r\n)。应该是:~('\r' | '\n')*

    试试这样的东西(未经测试!):

    grammar myjson;
    
    prog
     : object+ EOF
     ;
    
    object
     : '{' (key_value (',' key_value)*)? '}'
     ;
    
    array
     : '[' (value (',' value)*)? ']'
     ;
    
    key_value
     : STRING ':' value
     ;
    
    value
     : object
     | array
     | STRING
     | NUMBER
     | BOOL
     | NULL 
     ;
    
    NULL
     : 'null'   
     ;
    
    BOOL
     : 'true'
     | 'false'
     ;
    
    STRING
      : '"' (UNICODE | SPECIAL)* '"'
      ;
    
    NUMBER
     : ('+'|'-')? DIGIT+ '.' DIGIT* EXPONENT?
     | ('+'|'-')? '.'? DIGIT+ EXPONENT?
     ;
    
    COMM
     : '//' ~('\r' | '\n')* {skip();}    
     | '/*' .* '*/'         {skip();}
     ;
    
    SPACE
     : (' ' | '\t' | '\r' | '\n' | '\u000c')+ {skip();}
     ;
    
    fragment
    DIGIT
     : '0'..'9' 
     ;
    
    fragment 
    EXPONENT 
     : ('e' | 'E') ('+' | '-') ? DIGIT+ 
     ;
    
    fragment
    UNICODE
     : ~('\u0022' | '\u005C') 
     ;
    
    fragment
    SPECIAL     
     : '\u005C' ( '"' | '\u005C'  | '\u002F'
                | 'b' | 'f' | 'n' | 'r'
                | 't' | 'u' DIGIT DIGIT DIGIT DIGIT
                )
     ;
    

    还检查来自 ANTLR Github 存储库的 JSON 语法:https://github.com/antlr/grammars-v4/blob/master/json/Json.g4 虽然是 ANTLR4 语法,但它看起来与 ANTLR 3 兼容。

    【讨论】:

    • 感谢您的及时回复。我已经设法让它发挥作用。似乎当我得到“在这个流中不能向后看一个以上的标记”时,是因为 ~('\r'? '\n') 规则,你解释了如何使它在你的答案中起作用。跨度>
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多