ANTLR输入与语法匹配但程序无法实现

时间:2012-07-13 09:39:44

标签: antlr antlr3 secs

我正在为SML消息编写解析器。输入:包含许多SML消息的文件。输出:具有已标识元素的消息队列。这是我的代码:

grammar SML;
options {language = Java;}
@header {
  package SECSParser;
 import SECSParser.SMLLexer;
}

@lexer::header {
  package SECSParser;
}

@parser::members {
  public static void main(String[] args) throws Exception {
    String file = "C:\\Messages.sml";
    SMLLexer lexer = new SMLLexer(new ANTLRFileStream(file));
    SMLParser parser = new SMLParser(new CommonTokenStream(lexer));
    parser.program();
  }
}

@lexer::members {
  public static String place = "end";
  public static void setPlace(String text) { SMLLexer.place = text; }
  public static String getPlace() {return SMLLexer.place;}
  public static boolean placeIsType() {
    return (SMLLexer.place.equals("wb")
    | SMLLexer.place.equals("value")
    | SMLLexer.place.equals("type"));
  }
  public static boolean placeIsStreamFunction() {
    return (SMLLexer.place.equals("sf") | SMLLexer.place.equals("name"));
  }
  public static boolean placeIsWaitBit() {
    return (SMLLexer.place.equals("sf") | SMLLexer.place.equals("wb"));
  }
  public boolean ahead() {
    if ((input.LA(-2) == 'S') || (input.LA(-2) == 's')) {
      return false;
    }
    return true;
  }
}

program:(message)* EOF;
message:{System.out.println("MESSAGE     : \n");}
  {SMLLexer.setPlace("name");}
  name ws* ':' ws* {SMLLexer.setPlace("sf");} str_func 
  (ws+ {SMLLexer.setPlace("wb");} waitbit)? (ws+ item)? '.' 
   ws* {SMLLexer.setPlace("end");};

name:LETTER(LETTER| NUMBER| '_')* {System.out.println("NAME     : " + $text + "\n");};
fragment STR:~('\'' | '\"');
NUMBER:'0'..'9';
LETTER:(('A'..'Z') | ('a'..'z'));
str_func: (('S' | 's') stream ('F' | 'f') function);
stream: NUMBER+ {System.out.println("STREAM     : " + $text + "\n");};
function: NUMBER+ {System.out.println("FUNCTION     : " + $text + "\n");};
waitbit: {SMLLexer.placeIsWaitBit()}?=>('W' | 'w') {
  System.out.println("WAITBIT     : " + $text + "\n");
};
item:{System.out.println("ITEM     : \n");} ws* SITEM ws* {SMLLexer.setPlace("type");}
  TYPE ( (ws* '[' number_item ']')? ws+ {SMLLexer.setPlace("value");}value)? 
  ws* EITEM ws* COMMENT? ws*;
SITEM: '<' {SMLLexer.setPlace("type");};
EITEM: '>';
TYPE:{SMLLexer.placeIsType()}?=>( 'A' | 'a' | 'L'| 'l'| 'BINARY'| 'binary'| 'BOOLEAN'| 'boolean'| 'JIS'| 'jis'| 'I8'| 'i8' | 'I1'| 'i1'| 'I2'| 'i2' | 'I4'| 'i4'| 'F4'| 'f4'| 'F8'| 'f8'| 'U8'| 'u8' | 'U1'| 'u1'| 'U2' | 'u2'| 'U4'| 'u4' ){System.out.println("TYPE     : " + $text + "\n");};
number_item: NUMBER+ {System.out.println("NUMBER ITEM     : " + $text + "\n");};
value:(item ws*)+| (string ws*)+| ((LETTER| NUMBER)ws*)+;
COMMENT:('/*' (options {greedy=false;}: .)* '*/') {$channel = HIDDEN;};
string:('\'' STR? '\'')| ('\"' STR? '\"') {System.out.println("VALUE     : " + $text + "\n");};
ANY:.;
ws:(' '| '\t'| '\r'| '\n'| '\f');

这是我的文件“Message.sml”

Are_You_There1l : S1F4 W.
On_Line_Data:S1F4 W
<L[2]
    <U4 13>
    <U4 7>
>.
W1Are_You_There: S1F4 W.

结果是:

MESSAGE     : 
NAME     : Are_You_There1l
STREAM     : 1
FUNCTION     : 4
WAITBIT     : W
MESSAGE     : 
NAME     : On_Line_Data
STREAM     : 1
FUNCTION     : 4
WAITBIT     : W
ITEM     : 
MESSAGE     : 
NAME     : L
TYPE     : U4
TYPE     : U4
MESSAGE     : 
NAME     : Are_You_There
STREAM     : 1
FUNCTION     : 4
WAITBIT     : W

**C:\Messages.sml line 4:1 mismatched input 'L' expecting TYPE
C:\Messages.sml line 4:2 mismatched input '[' expecting ':'**

我不知道为什么我的程序无法实现TYPE:'L'??我试过TYPE'U4',它有效。

1 个答案:

答案 0 :(得分:0)

能够为您的问题提供答案有太多问题。即使您的问题得到了解答,它也没有任何帮助,因为语法包含太多错误。我建议扔掉它并重新开始。但在重新开始之前,请先阅读几句ANTLR tutorials或获取The Definitive ANTLR Reference的副本。

一些问题:

  • 您似乎不知道解析器和词法分析器规则之间的区别。你的一些解析器规则应该是词法分析器规则,你的一些词法分析器规则应该是解析器规则;
  • 你在解析器规则中使用片段规则:这将永远不会起作用,因为片段规则永远不会变成令牌。片段规则只能用于词法分析器规则(或其他片段规则);
  • 你是从解析器设置(静态)词法变量:你不能这样做!解析器自己缓冲令牌将导致你的逻辑出现严重错误。词法分析器和解析器之间存在严格的分离:词法分析器只生成令牌而不受解析器的任何干扰! Lexing是一个单独的过程。如果您确实需要,请选择ANTLR以外的其他内容(Google用于“无扫描器解析”,“PEG”和/或“packrat”)。此问题很可能是'L'在您的特定情况下未被标记为TYPE的原因;
  • 您使用的是文字标记,例如('W' | 'w'),还有LETTER作为词法分析器规则。但是,单个'w''W'现在永远不会被标记为LETTER。在解析器规则中定义文字标记或多或少与执行:

    相同

    W : 'w' | 'W';
    LETTER : 'a'..'z' | 'A'..'Z'; // this will never match a 'w' or 'W' now!

    这也与ANTLR的词法分析器独立于解析器的操作有关。

再说一遍:在继续IMO之前,你真的需要掌握基础知识。

祝你好运!