2

我想为与以下 samba 配置文件非常相似的文档创建解析器。它有很多部分,每个部分都有一个标题行,以 [ 开头,后跟关键字部分名称,例如 global、share_name 等,直到行尾。节标题行之后是此节的参数。我们不知道一个节的结尾,直到我们到达另一个节的开头换行[..,我怎样才能为这种文档编写规则?我发现的所有 antlr 示例都确切地知道何时开始一个部分以及何时结束一个部分。非常感谢!

[global]
    netbios name = NETBIOS_NAME
    workgroup = WORKGROUP
    security = user
[SHARE_NAME]
    comment = COMMENT
    force create mode = 0770
    locking = yes
[printers]
    comment = COMMENT
    path = /var/spool/samba
    browseable = No

这是我的语法:

grammar SambaConfiguration;

file    :   global_section
    share_name_section
    printer_section
    EOF
;

global_section 
    :   SECTION_TAG_START GLOBAL_SECTION_TAG (.)* SECTION_TAG_END NEW_LINE
    (~SECTION_TAG_START (.)* NEW_LINE)*
    ;

share_name_section 
    :   SECTION_TAG_START SHARE_NAME_SECTION_TAG (.)*  SECTION_TAG_END NEW_LINE
    ((~SECTION_TAG_START) (.)* NEW_LINE)*
    ;

printer_section
    :   SECTION_TAG_START PRINTER_SECTION_TAG (.)* SECTION_TAG_END NEW_LINE
    ((~SECTION_TAG_START) (.)* NEW_LINE)*
    ;

SECTION_TAG_START 
    :   '['
    ;

SECTION_TAG_END
    :   ']'
    ;

GLOBAL_SECTION_TAG
    :   'global' 
    ;

SHARE_NAME_SECTION_TAG 
    :   'SHARE_NAME' 
    ;

PRINTER_SECTION_TAG 
    :   'printer'
    ;   


NEW_LINE :
    '\r' ? '\n' | '\r'
    ;
WHITE_SPACE 
    :   ' ' | '\t'
    ;

不知何故,它无法正常工作。在 Antlrworks 中运行时,它给了我以下异常:

在 12:19 NoViableAltException('o'@[1:1: Tokens : (SECTION_TAG_START | SECTION_TAG_END | GLOBAL_SECTION_TAG | SHARE_NAME_SECTION_TAG | PRINTER_SECTION_TAG | NEW_LINE | WHITE_SPACE);])

谢谢。

4

1 回答 1

1

错误信息:

在 12:19 NoViableAltException('o'@[1:1: Tokens : (SECTION_TAG_START | SECTION_TAG_END | GLOBAL_SECTION_TAG | SHARE_NAME_SECTION_TAG | PRINTER_SECTION_TAG | NEW_LINE | WHITE_SPACE);])

意味着 ANTLR 遇到一个字符 , 'o',它不能为其创建标记。您可能认为它会与.解析器规则中的 匹配,但事实并非如此。在解析器规则中,.匹配任何标记,而只有在词法分析器规则中,它匹配任何字符。

您的词法分析器仅创建以下标记:SECTION_TAG_STARTSECTION_TAG_ENDGLOBAL_SECTION_TAGSHARE_NAME_SECTION_TAGPRINTER_SECTION_TAG和。因此,解析器规则内部的一个匹配这些标记中的任何一个,仅此而已。NEW_LINEWHITE_SPACE.

除非你这样做是为了学习 ANTLR,否则我会犹豫使用 ANTLR 来完成这项任务。您可以通过一些内置的字符串操作和逐行读取输入来更轻松地做到这一点。

使用 ANTLR,您可以执行类似的操作:

grammar T;

parse
 : section* EOF
 ;

section
 : header line*
 ;

header
 : SECTION_TAG_START name=text SECTION_TAG_END NEW_LINE
   {
     System.out.println("name=" + $name.text);
   }
 ;

line
 : key=text ASSIGN value=text (NEW_LINE | EOF)
   {
     System.out.println("  key=`" + $key.text.trim() + 
         "`, value=`" + $value.text.trim() + "`");
   }
 ;

text
 : OTHER+
 ;

SECTION_TAG_START : '[';
SECTION_TAG_END   : ']';
ASSIGN            : '=';
NEW_LINE          : '\r'? '\n';
OTHER             : . /* any other char: must be the last rule! */;

解析您的示例输入会将以下内容打印到您的控制台:

名称=全局
  键=`netbios 名称`,值=`NETBIOS_NAME`
  键=`工作组`,值=`工作组`
  键=`安全`,值=`用户`
名称=SHARE_NAME
  键=`评论`,值=`评论`
  key=`强制创建模式`, value=`0770`
  键=`锁定`,值=`是`
名称=打印机
  键=`评论`,值=`评论`
  键=`路径`,值=`/var/spool/samba`
  键=`可浏览`,值=`否`
于 2013-01-25T18:38:39.667 回答