5

我想为一种简单的语言定义一个语法。

该语言允许某种类型的分配。

例子

keyworda: this is the 1 keyword-A
keywordb: this is the second keywordb
...

问题是,在关键字和':'any char 之后应该是可能的(关键字也是)

我已经尝试了很多东西,但我认为我仍然不喜欢词法分析器和解析器的思考......

我的最后一个想法失败了:

rule 
  :  'keyworda' ':' anychar* 'keywordb' ':' anychar* EOF 
  ;

anychar
  :  .
  ;

NEWLINE
  :  ('\r'? '\n') {$channel=HIDDEN;}
  ;

编辑

首先:感谢您的回答!

我通读了手册并查看了 scott stanchfield 的教程。

问题是,我没有得到“anychar”的东西!

你是对的,我上面写的语法是错误的,因为我很着急。

这是一个更好的尝试。问题仍然是,Tokenizer 在定义 ala 中识别例如关键字

keyworda : this is keyworda.
keywordb : this is another key!
...

语法:

rule
    :   KEYA ':' STRING_LITERAL* NEWLINE
        keybdefinition*
         EOF
    ;

keybdefinition
    :   KEYB ':' STRING_LITERAL* NEWLINE
    ;


KEYA: 'keyworda';
KEYB:'keywordb';
STRING_LITERAL: 'a'..'z' | 'A'..'Z' | '0'..'9' | ':' | '.' | '&' | '/' | '\\' | ';';

NEWLINE: '\r'? | '\n'; 
SPACE:  (' ' | '\t') {$channel=HIDDEN;};

编辑二

哦,我的上帝,按照你解释的方式做这件事很明显。不知道为什么我自己没有得到它!非常感谢蒂姆的解释!

我还有一个问题:如果我为词法分析器定义我的标记,为解析器定义我的语法。它是在树解析器还是在解析器本身中检查语义的常用方法?

例如,假设我定义了与您发布的相同的语法。

keyworda : ab
keywordb : xy
keyworda : ab1
keywordb : xy1
...

现在我想检查在每个关键字a 定义之后是否定义了关键字b。稍后我确实想检查该值是否正确的含义。假设我们确实有一个关键字extends:'keyword value',我需要检查'keyword value'是否已经定义。

我可以通过两种方式做到这一点:首先,更改解析器的语法规则并在此处添加用于检查的 java 代码。其次,语法保持原样,我定义了一个树解析器语法来检查这些条件。

我真的不知道哪种方式更好,有什么优点或缺点......

非常感谢你的帮助

4

1 回答 1

19

.词法分析器和解析器规则中具有不同的含义。在词法分析器规则中,它匹配范围\u000...中的任何字符\uFFFF。在解析器规则中,.匹配任何标记。

请注意,词法分析器规则以大写字母开头,而解析器规则以小写字母开头。您还可以在解析器规则中创建标记(词法分析器规则)作为文字。这意味着您的语法只会创建 4 个不同的标记(实际上是 3 个,因为NEWLINE是“隐藏的”):

  • 'keyworda'
  • ':'
  • 'keywordb'
  • NEWLINE(已从默认令牌流中删除)

EOF是内置令牌)

因此,这使您的anychar规则匹配'keyworda',':''keywordb', 而不是您可能期望的任何字符。

key ':' value此外,您似乎通过换行符分隔您的- 条目,但您在词法分析阶段删除了换行符。通过删除它们,您应该如何知道 a 的结尾value是什么以及 a 的开头key是什么?您的令牌流将是一个连续的关键字流,任何字符冒号,因此无法判断关键字何时真的是关键字,或者是value(右侧':')的一部分。为此,您需要一个换行符。

看起来您已经开始使用 ANTLR,但并不真正知道自己在做什么:IMO,这不是学习这个特定工具的方法。我建议在继续之前获取一份The Definitive ANTLR Reference或阅读/查看一些ANTLR 教程

祝你好运!

编辑

下面是如何让关键字也成为您的“价值”的一部分的快速演示:

文件:TG

grammar T;

parse
  :  line+ EOF
  ;

line
  :  key COLON value eol 
     {System.out.printf("key='\%s', value='\%s'\n", $key.text, $value.text);}
  ;

value
  :  any_except_newline*
  ;

key
  :  KEYA
  |  KEYB
  ;

any_except_newline
  :  COLON
  |  KEYA
  |  KEYB
  |  WORD
  |  ANYCHAR
  ;

eol
  :  NEWLINE
  |  EOF
  ;

COLON   : ':';
KEYA    : 'keyworda';
KEYB    : 'keywordb';
WORD    : ('a'..'z' | 'A'..'Z')+;
NEWLINE : '\r'? '\n' | '\r';
SPACE   : (' ' | '\t') {$channel=HIDDEN;};
ANYCHAR : .; 

文件:Main.java

import org.antlr.runtime.*;

public class Main {
  public static void main(String[] args) throws Exception {
    String source = 
        "keyworda : this is keyworda.\n" + 
        "keywordb : this is another key!";
    TLexer lexer = new TLexer(new ANTLRStringStream(source));
    TParser parser = new TParser(new CommonTokenStream(lexer));
    parser.parse();
  }
}

如果您现在通过执行以下操作运行演示:

java -cp antlr-3.3.jar org.antlr.Tool T.g
javac -cp antlr-3.3.jar *.java
java -cp .:antlr-3.3.jar Main

您会看到以下内容被打印到控制台:

key='keyworda', value='this is keyworda.'
key='keywordb', value='this is another key!'
于 2011-09-02T18:54:27.073 回答