Xtext:阻止匹配来自其他规则的关键字

时间:2015-11-26 09:34:56

标签: xtext

我正在寻找一种方法来防止在不期望这些KEYWORDS的地方进行KEYWORDS匹配。

看看下面的语法。 “ APPLY ”和“ OUTPUT ”都是关键字。 ' OUTPUT '的参数包含任何字符。

一切正常但如果此参数包含单词 APPLY ,则会引发错误(外部输入APPLY期待RULE_END)。

有没有办法解决这个问题? 感谢。

示例文字

APPLY, 'an id' $
OUTPUT, A text $
OUTPUT, A text with the word APPLY $

DSL

grammar org.xtext.example.mydsl.MyDsl with org.eclipse.xtext.common.Terminals

generate myDsl "http://www.xtext.org/example/mydsl/MyDsl"

Model:
    statement+=Statement*;

Statement:
    ApplyStatement | OutputStatement;

OutputStatement:
    'OUTPUT' ',' out+=EXTENDLABEL* end=END;

ApplyStatement:
    'APPLY' ',' id=LABELIDENTIFIER end=END;

terminal fragment LETTER:
    'A' | 'B' | 'C' | 'D' | 'E' | 'F' | 'G' | 'H' | 'I' | 'J' | 'K' | 'L' | 'M' | 'N' | 'O' | 'P' | 'Q' | 'R' | 'S' | 'T'
    | 'U' | 'V' | 'W' | 'X' | 'Y' | 'Z' | 'a' | 'b' | 'c' | 'd' | 'e' | 'f' | 'g' | 'h' | 'i' | 'j' | 'k' | 'l' | 'm' |
    'n' | 'o' | 'p' | 'q' | 'r' | 's' | 't' | 'u' | 'v' | 'w' | 'x' | 'y' | 'z';

terminal LABELIDENTIFIER:
    "'"->"'";

terminal EXTENDLABEL:
    (LETTER) (LETTER)*;

terminal END:
    '$' !('\n' | '\r')*;

2 个答案:

答案 0 :(得分:0)

我看到了一些可以解决问题的方法。首先,您可以逃避出现的关键字,例如Xbase语言使用'^'字符作为转义字符;如果由于任何原因编写关键字时出现问题,可以在前面加上“^”,这样就可以了。同样,如果您将字符串放在特定符号中,例如撇号,它会有很大帮助。当然,这些解决方案需要改变您自己的语言,您可能会或可能不会这样做。

您也可以使用数据类型规则替换EXTENDLABEL终端。这为解决冲突提供了更大的灵活性;在最坏的情况下,您可以添加语言关键字作为选项我通过切线related case in the Eclipse forums建议了这条路线。

答案 1 :(得分:0)

另一个解决方案是在解析器使用它之前更改令牌的ID。令牌由词法分析器提供,您的解析器将在输入中使用这些令牌来生成AST。因此,我们的想法是在将标记传递给解析器之前更改标记。

要做到这一点,你需要声明自己的解析器:

@Override
public Class<? extends IParser> bindIParser() {
    return ModelParser.class;
} 

注意:您的解析器将扩展您生成的语法解析器。

然后你需要覆盖以下方法来介绍你自己的TokenSource:

override protected XtextTokenStream createTokenStream(TokenSource tokenSource) {
    return new TokenSource(tokenSource, getTokenDefProvider());
} 

您拥有令牌源需要扩展'XtextTokenStream'。

需要覆盖方法'LT'后如下:

override LT(int k) {
    var Token token = super.LT(k)
    if(token != null && token.text != null) token.tokenOverride(k);
    token
}

然后你只需要更改ID:

def void tokenOverride(Token token, int index){
    switch (token.text){
        case "APPLY" : {
            overrideType(t_parameter, InternalModelParser.RULE_ID);
        }
    }
 }

def void overrideType(Token token, int i) {
    token.type = i
}

注意:不要忘记在更改令牌ID之前添加条件,在此示例中,所有令牌“APPLY”将成为ID。

当然,在交换机内部,您可以使用令牌“应用”的ID代替令牌的文本。