ANTLR的BibTex语法解析器

6
我正在寻找一份ANTLR格式的bibtex语法,以在一个业余项目中使用。我不希望花费时间编写ANTLR语法(因为这需要学习曲线,可能需要很长时间)。所以,我会感激任何指引。
注意:我已经找到了用于bison和yacc的bibtex语法,但没有找到antlr的语法。
编辑:正如Bart指出的那样,我不需要解析引言字符串中的前导和tex。

1
你需要它有多准确/精确?前导内容可能很混乱,难以解析,在引号或大括号内部,你可以正式嵌入类似于这样的“数学”代码:"text $2 \times \pi$ text",据我所知。你是否也想解析所有这些内容,或者前导内容和引用(或大括号)的内容可以被标记为单个标记? - Bart Kiers
嗨Bart,感谢你的指引。我不需要解析bibtex中的文本,并且引用(或引用或前置)文本也可以作为单个标记进行标记化。 - systemsfault
如果您需要的是(不太准确的BibTex语法),那么我可能恰好有。让我为您整理一下,并编写一个小测试类。 - Bart Kiers
jBibTeX 是一个完整的处理 BibTeX 文件的库。是否需要单独的语法呢? - koppor
1个回答

9
这是一个(非常)基础的BibTex语法,输出一棵AST(与简单的解析树相反):
grammar BibTex;

options {
  output=AST;
  ASTLabelType=CommonTree;
}

tokens {
  BIBTEXFILE;
  TYPE;
  STRING;
  PREAMBLE;
  COMMENT;
  TAG;
  CONCAT;
}

//////////////////////////////// Parser rules ////////////////////////////////
parse
  :  (entry (Comma? entry)* Comma?)? EOF             -> ^(BIBTEXFILE entry*)
  ;

entry
  :  Type Name Comma tags CloseBrace                 -> ^(TYPE Name tags)
  |  StringType Name Assign QuotedContent CloseBrace -> ^(STRING Name QuotedContent)
  |  PreambleType content CloseBrace                 -> ^(PREAMBLE content)
  |  CommentType                                     -> ^(COMMENT CommentType)
  ;

tags
  :  (tag (Comma tag)* Comma?)?                      -> tag*
  ;

tag
  :  Name Assign content                             -> ^(TAG Name content)
  ;

content
  :  concatable (Concat concatable)*                 -> ^(CONCAT concatable+)
  |  Number
  |  BracedContent
  ;

concatable
  :  QuotedContent
  |  Name
  ;

//////////////////////////////// Lexer rules ////////////////////////////////
Assign
  :  '='
  ;

Concat
  :  '#'
  ;

Comma
  :  ','
  ;

CloseBrace
  :  '}'
  ;

QuotedContent
  :  '"' (~('\\' | '{' | '}' | '"') | '\\' . | BracedContent)* '"'
  ;

BracedContent
  :  '{' (~('\\' | '{' | '}') | '\\' . | BracedContent)* '}'
  ;

StringType
  :  '@' ('s'|'S') ('t'|'T') ('r'|'R') ('i'|'I') ('n'|'N') ('g'|'G') SP? '{'
  ;

PreambleType
  :  '@' ('p'|'P') ('r'|'R') ('e'|'E') ('a'|'A') ('m'|'M') ('b'|'B') ('l'|'L') ('e'|'E') SP? '{'
  ;

CommentType
  :  '@' ('c'|'C') ('o'|'O') ('m'|'M') ('m'|'M') ('e'|'E') ('n'|'N') ('t'|'T') SP? BracedContent
  |  '%' ~('\r' | '\n')*
  ;

Type
  :  '@' Letter+ SP? '{'
  ;

Number
  :  Digit+
  ;

Name
  :  Letter (Letter | Digit | ':' | '-')*
  ;

Spaces
  :  SP {skip();}
  ;

//////////////////////////////// Lexer fragments ////////////////////////////////
fragment Letter
  :  'a'..'z'
  |  'A'..'Z'
  ;

fragment Digit
  :  '0'..'9'
  ;

fragment SP
  :  (' ' | '\t' | '\r' | '\n' | '\f')+
  ;  

(如果您不需要AST,请删除所有 -> 及其右侧的内容,并删除 options {...} 和 tokens {...} 块)

可以使用以下类进行测试:

import org.antlr.runtime.*;
import org.antlr.runtime.tree.*;
import org.antlr.stringtemplate.*;

public class Main {
  public static void main(String[] args) throws Exception {

    // parse the file 'test.bib'
    BibTexLexer lexer = new BibTexLexer(new ANTLRFileStream("test.bib"));
    BibTexParser parser = new BibTexParser(new CommonTokenStream(lexer));

    // you can use the following tree in your code
    // see: http://www.antlr.org/api/Java/classorg_1_1antlr_1_1runtime_1_1tree_1_1_common_tree.html
    CommonTree tree = (CommonTree)parser.parse().getTree();

    // print a DOT tree of our AST
    DOTTreeGenerator gen = new DOTTreeGenerator();
    StringTemplate st = gen.toDOT(tree);
    System.out.println(st);
  }
}

以下是示例Bib输入(文件:test.bib):

@PREAMBLE{
  "\newcommand{\noopsort}[1]{} "
  # "\newcommand{\singleletter}[1]{#1} " 
}

@string { 
  me = "Bart Kiers" 
}

@ComMENt{some comments here}

% or some comments here

@article{mrx05,
  auTHor = me # "Mr. X",
  Title = {Something Great}, 
  publisher = "nob" # "ody",
  YEAR = 2005,
  x = {{Bib}\TeX},
  y = "{Bib}\TeX",
  z = "{Bib}" # "\TeX",
},

@misc{ patashnik-bibtexing,
       author = "Oren Patashnik",
       title = "BIBTEXing",
       year = "1988"
} % no comma here

@techreport{presstudy2002,
    author      = "Dr. Diessen, van R. J. and Drs. Steenbergen, J. F.",
    title       = "Long {T}erm {P}reservation {S}tudy of the {DNEP} {P}roject",
    institution = "IBM, National Library of the Netherlands",
    year        = "2002",
    month       = "December",
}

运行演示

如果您现在从语法中生成解析器和词法分析器:

java -cp antlr-3.3.jar org.antlr.Tool BibTex.g

并编译所有的.java源文件:

javac -cp antlr-3.3.jar *.java

最终运行Main类:

*nix/MacOS

java -cp .:antlr-3.3.jar Main

Windows

java -cp .;antlr-3.3.jar Main

你将在控制台看到一些输出,这些输出对应于以下的AST:

enter image description here

(点击图像可放大,生成于 graphviz-dev.appspot.com)

需要强调的是:我没有进行过语法测试!我写了一段时间,但从未在任何项目中真正使用它。


1
那看起来是一个很好的起点。我正在寻找可以包含在Apache许可项目中的Java BibTex解析器。我猜想你打算将这个语法捐赠给公共领域,但为了记录,你能澄清一下你要发布的许可证是什么吗? - Tom Morris
@Tom,据我所知,在SE网站上发布的每个用户贡献都是根据知识共享许可证授权的。 - Bart Kiers
谢谢你的快速回复,巴特。我忘记了服务条款CC-BY-SA 3.0会适用。现在我需要弄清楚它是否与BSD许可证兼容(我之前说错了,应该是Apache)。我怀疑它可能不兼容。 - Tom Morris
3
@Tom,没问题。我们假装你刚给我发了一封电子邮件,我更改了一些语法并将这个语法发送给了你。你有我的(书面)许可,可以添加任何类似于开源的许可证。如果你需要更正式的书面同意,请给我发一封信(我的电子邮件在我的个人资料中),我会将语法与我的授权一起通过电子邮件发送给你,以便你可以以最适合你的方式进行许可。 - Bart Kiers

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接