如何定义一个令牌,它是集合A中的所有字符,除了子集B中的那些字符?

时间:2015-08-31 05:44:50

标签: antlr4 lexer

RFC2616(HTTP / 1.1)中,“2.2基本规则”一节中“令牌”的定义如下:

token          = 1*<any CHAR except CTLs or separators>

从那一节开始,我有以下片段,现在我想定义'TOKEN':

lexer grammar AcceptEncoding;

TOKEN: /* (CHAR excluding (CTRL | SEPARATORS)) */

fragment CHAR: [\u0000-\u007f];
fragment CTRL: [\u0000-\u001f] | \u007f;
fragment SEPARATORS: [()<>@,;:\\;"/\[\]?={|}] | SP | HT;
fragment SP: ' ';
fragment HT: '\t';

对于TOKEN的定义,我如何估计我的假设“排除”运算符?

3 个答案:

答案 0 :(得分:1)

ANTLR中没有设置/范围数学。您只能通过OR运算符组合多个集/范围。许多不相交范围的典型规则如下:

fragment LETTER_WHEN_UNQUOTED:
    '0'..'9'
    | 'A'..'Z'
    | '$'
    | '_'
    | '\u0080'..'\uffff'
;

答案 1 :(得分:0)

一种方法是对字符集进行“数学运算”,以便我们可以定义只能组合字符的词法规则:

lexer grammar RFC2616;

TOKEN: (DIGIT | UPALPHA | LOALPHA | NON_SEPARATORS)+

/* 
 * split up ASCII 0-127 into 'atoms' of 
 * relevance per '2.2 Basic Rules'.  Regions
 * not requiring to be referenced are not 
 * given a name.
 */

//                [\u0000-\u0008];  /* (control chars) */
fragment HT:      '\u0009';         /* (tab) */
fragment LF:      '\u0010';         /* (LF) */
//                 [\u0011-\u0012];  /* (control chars) */
fragment CR:      '\u0013';         /* (CR)
//                [\u0014-\u001f];  /* (control chars) */
fragment SP:      '\u0020';         /* (space) */
//                [\u0021-\u02f];   /* !"#$%'()*+,-./  */
fragment DIGIT:   [u0030-\u0039];   /* 01234556789  */
//                [\u003a-\u0040];  /* :;<=>@  */
fragment UPALPHA: [\u0041-\u005a];  /* ABCDEFGHIGJLMNOPQRSTUVWXYZ  */
//                [\u005b-\u0060];  /* [\]^_` */
fragment LOALPHA: [\u0061-\u0071];  /* abcdefghijklmnopqrstuvwxyz  */
//                [\u007b-\u007e];  /* {|}~ */
//                '\u007f';         /* (del) */

/* 
 * Considering 'all relevant gaps' and the characters we 
 * cannot use per RFC 2616 Section 2.2 Basic Rules definition 
 * of 'separators', what does that leave us with?  
 * (manually determined)
 */
fragment SEPARATORS: [()<>@,;:\\;"/\[\]?={|}];
fragment NON_SEPARATORS: [!#$%&'*+-.^_`~*];

我发现这种方法并不特别令人满意。 RFC 2616中的另一条规则希望定义为:

TEXT: <any OCTET except CTLs, but including LWS>
qdtext = <any TEXT except <">>

这会迫使我进一步重构上面的权宜之计'SEPARATORS'令牌,如:

fragment QUOT: '"';
fragment SEPARATORS_OTHER_THAN_QUOT: [()<>@,;:\\;/\[\]?={|}];
fragment SEPARATORS: SEPARATORS_OTHER_THAN_QUOT | QUOT;

fragment LWS: SP | HT;

TEXT: DIGIT | UPALPHA | LOALPHA | LWS | SEPARATORS | NON_SEPARATORS;
QDTEXT: DIGIT | UPALPHA | LOALPHA | LWS | SEPARATORS_OTHER_THAN_QUOT | NON_SEPARATORS;

也许这是编写词法分析器的一部分,并且无法避免,但感觉更像是以错误的方式解决问题!

(注意:我不会将此答案标记为'正确'。)

答案 2 :(得分:0)

受到来自@ mike-lischke的答案的刺激(因为LETTER_WHEN_UNQUOTED真的感觉还是错的),我在其他语法中寻找对引用的字符串文字进行肯定常见的处理。在Terrence Parr自己的Java 1.6 ANTLR3 grammar(呃,没有正确地作为text/plain)(通过ANTLR3 Grammar List),他可以获得除#39以外的任何角色的比赛;词法分析器规则中的波浪号运算符~

STRINGLITERAL
    :   '"' 
        (   EscapeSequence
        |   ~( '\\' | '"' | '\r' | '\n' )        
        )* 
        '"' 
    ;
// Copyright (c) 2007-2008 Terence Parr and possibly Yang Jiang.
  

注意:上述代码是根据BSD许可证授权的,但我在BSD许可下重新分发此片段(因为此帖子本身在CC-BY-SA下)。相反,我在“合理使用”的条款中使用它。据我所知。

因此~为我提供了一个选项来表达:&#39; Unicode中的所有字符,但设置B&#39;中的字符除外。 &#34;恼人的我不会选择被排除在&#34;之外的那套,我想。但后来我意识到了

TOOHIGH: [\u007f-\uffff];
TOKEN: (~( TOOHIGH | SP | HT | CTRL | SEPARATORS ))+

......应该没事。虽然在实践中,ANTLR4并不喜欢&#39; lexer子规则出现在&#39; sets&#39;中,并且只处理文字集,因此最终变为:

TOKEN:
/* this is given in '2.2 Basic Rules' as:
 *
 *   token          = 1*<any CHAR except CTLs or separators>
 *
 * which I am reducing down to:
 * any character in ASCII 0-127 but _excluding_
 *   CTRL (0-31,127)
 *   SEPARATORS
 *   space (32)
 *   and tab (9)   (which is a CTRL character anyhow)
 */
 ( ~( [\u0000-\u001f] | '\u007f' /*CTRL,HT*/ | [()<>@,;:\\;"/\[\]?={|}] /*SEPARATORS*/ | '\u0020' /*SP*/ | [\u0080-\uffff] /*NON_ASCII*/))*
;

诀窍是用including the set I do want(Unicode 128 +)来表达excluding the set I don't want(Unicode 0-127)。

这比我的其他答案简洁得多。如果确实有效,我会将其标记为正确。