c# - ANTLR:我可以让 ',' 成为一个上下文中的一个标记,而另一个在所述上下文之外吗?

标签 c# parsing antlr antlr3 lexical-analysis

具体来说,我正在尝试在 ANTLR 中实现一个 RegExp 解析器。

以下是我语法的相关部分:

grammar JavaScriptRegExp;
options {
    language = 'CSharp3';
}

tokens {
    /* snip */
    QUESTION = '?';
    STAR = '*';
    PLUS = '+';
    L_CURLY = '{';
    R_CURLY = '}';
    COMMA = ',';
}

/* snip */

quantifier returns [Quantifier value]
    :   q=quantifierPrefix QUESTION?
        {
            var quant = $q.value;
            quant.Eager = $QUESTION == null;
            return quant;
        }
    ;

quantifierPrefix returns [Quantifier value]
    :   STAR { return new Quantifier { Min = 0 }; }
    |   PLUS { return new Quantifier { Min = 1 }; }
    |   QUESTION { return new Quantifier { Min = 0, Max = 1 }; }
    |   L_CURLY min=DEC_DIGITS (COMMA max=DEC_DIGITS?)? R_CURLY
        {
            var minValue = int.Parse($min.Text);
            if ($COMMA == null)
            {
                return new Quantifier { Min = minValue, Max = minValue };
            }
            else if ($max == null)
            {
                return new Quantifier { Min = minValue, Max = null };
            }
            else
            {
                var maxValue = int.Parse($max.Text);
                return new Quantifier { Min = minValue, Max = maxValue };
            }
        }
    ;

DEC_DIGITS
    :   ('0'..'9')+
    ;

/* snip */

CHAR
    :   ~('^' | '$' | '\\' | '.' | '*' | '+' | '?' | '(' | ')' | '[' | ']' | '{' | '}' | '|')
    ;

现在,在花括号内部,我想将“,”标记为逗号,但在大括号外部,我想将其标记为 CHAR。

这可能吗?

这不是唯一发生这种情况的案例。我将有许多其他情况出现问题(十进制数字、字符类中的连字符等)

编辑:

我知道这叫做上下文相关的词法分析。这对 ANTLR 来说可能吗?

最佳答案

this is called context-sensitive lexing. Is this possible with ANTLR?

不,解析器不能“告诉”它需要处理的词法分析器,比方说,在解析期间的某个特定时间不同的数字。单独在词法分析器中可能存在一些上下文相关的词法分析,但解析器不能影响词法分析器。

然而,它可以通过一些额外的解析器规则轻松解决。例如,在匹配字符类 ([ ... ]) 时,您使用匹配字符类中任何有效内容的解析器规则:

char_class
 : LBRACK char_class_char+ RBRACK
 ;

// ...

char_class_char
 : LBRACK // the '[' is not special inside a character class!
 | LBRACE // the '{' is not special inside a character class!
 | RBRACE // the '}' is not special inside a character class!
 | PLUS   // the '+' is not special inside a character class!
 | STAR   // the '*' is not special inside a character class!
 | QMARK  // the '?' is not special inside a character class!
 | COMMA
 | DIGIT
 | OTHER
 ;

一个小演示:

grammar T;

parse
 : atom* EOF
 ;

atom
 : unit quantifier?
 ;

unit
 : char_class
 | single_char
 ;

quantifier
 : greedy (PLUS | QMARK)?
 ;

greedy
 : PLUS
 | STAR
 | QMARK
 | LBRACE (number (COMMA number?)?) RBRACE
 ;

char_class
 : LBRACK char_class_char+ RBRACK
 ;

number
 : DIGIT+
 ;

single_char
 : DIGIT
 | COMMA
 | RBRACE
 | RBRACK // this is only special inside a character class
 | OTHER
 ;

char_class_char
 : LBRACK
 | LBRACE
 | RBRACE
 | PLUS
 | STAR
 | QMARK
 | COMMA
 | DIGIT
 | OTHER
 ;

LBRACK : '[';
RBRACK : ']';
LBRACE : '{';
RBRACE : '}';
PLUS   : '+';
STAR   : '*';
QMARK  : '?';
COMMA  : ',';
DIGIT  : '0'..'9';
OTHER  : . ;

它将解析输入 "[+*]{5,20}?A*+" 如下:

enter image description here

可以在这里找到更完整的 PCRE 语法:https://github.com/bkiers/PCREParser (语法可见here)

编辑

That it, I would prefer to tokenize "," as COMMA inside of the curly braces, but tokenize it as CHAR outside. I will use the workaround for now, but is that possible?

不,就像我说的:词法分析器不会受到解析器的影响。如果你想要这个,你应该去 PEG而不是 ANTLR。使用 ANTLR,词法分析和解析之间存在严格的分离:你对此无能为力。

但是,您可以只更改解析器规则中匹配的 token 类型。每个解析器规则都有一个 $start$end 标记,表示它匹配的第一个和最后一个标记。由于 char_class_char(和 single_char)将始终匹配单个标记,您可以在规则的 @after block 中更改标记的类型像这样:

single_char
@after{$start.setType(CHAR);}
 : DIGIT
 | COMMA
 | RBRACE
 | RBRACK // this is only special inside a character class
 | OTHER
 ;

char_class_char
@after{$start.setType(CHAR);}
 : LBRACK
 | LBRACE
 | RBRACE
 | PLUS
 | STAR
 | QMARK
 | COMMA
 | DIGIT
 | CHAR
 ;

// ...

CHAR : . ;

导致您所追求的行为(我猜)。

HTH

关于c# - ANTLR:我可以让 ',' 成为一个上下文中的一个标记,而另一个在所述上下文之外吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11487770/

相关文章:

C# xaml 图像未显示在应用程序中

c# - 如何将 List<string> 转换为 List<myEnumType>?

c# - 制作 NxN tic tac toe GUI wpf c#

java - 从依赖解析器中提取特殊节点

c# - ANTLR - 为 AST 编写树语法

c# - 我可以在 DLL 中嵌入其他文件吗?

java - 使用 GSON 解析嵌套的 JSON 数据

csv - 在 Java 中解析大型 CSV 文件的最快最有效的方法

解析不完整的语法

java - ANTLR - 语法和树语法之间的 token 枚举不匹配