Antlr3 - 非贪婪的双引号字符串与逃脱双引号

时间:2014-03-05 17:35:20

标签: parsing antlr antlr3 lexer

以下Antlr3语法文件不支持转义双引号作为STRING词法分析器规则的一部分。有什么想法吗?

表达工作:

  • \ “你好\”
  • REF(\ “你好\”,\ “你好\”)

表达式不起作用:

  • \ “H \” E \ “L \” L \ “○\”
  • ref(\“hello \”,\“hel \”lo \“)

Antlr3语法文件在AntlrWorks中可运行:

grammar Grammar;

options
{
    output=AST;
    ASTLabelType=CommonTree;
    language=CSharp3;
}

public oaExpression
   : exponentiationExpression EOF!
   ;

exponentiationExpression
    :       equalityExpression ( '^' equalityExpression )*
    ;

equalityExpression
    :       relationalExpression ( ( ('==' | '=' ) | ('!=' | '<>' ) ) relationalExpression )*
    ;

relationalExpression
    :       additiveExpression ( ( '>' | '>=' | '<' | '<=' ) additiveExpression )*
    ;

additiveExpression
    :       multiplicativeExpression ( ( '+' | '-' ) multiplicativeExpression )*
    ;

multiplicativeExpression
    :       primaryExpression ( ( '*' | '/' ) primaryExpression )*
    ;

primaryExpression
    :       '(' exponentiationExpression ')' | value | identifier (arguments )?
    ;

value
    :       STRING
    ;

identifier
    :       ID
    ;

expressionList
    :       exponentiationExpression ( ',' exponentiationExpression )*
    ;

arguments
    :       '(' ( expressionList )? ')'
    ;                      

/*
 * Lexer rules
 */

ID
    :       LETTER (LETTER | DIGIT)*
    ;

STRING
    :       '"' ( options { greedy=false; } : ~'"' )* '"'
    ;

WS
    :       (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=Hidden;}
    ;

/*
 * Fragment Lexer rules
 */

fragment
LETTER
    :       'a'..'z'
    |       'A'..'Z'
    |       '_'
    ;

fragment
EXPONENT
    :       ('e'|'E') ('+'|'-')? ( DIGIT )+
    ;

fragment
HEX_DIGIT
    :       ( DIGIT |'a'..'f'|'A'..'F')
    ;

fragment
DIGIT
    :       '0'..'9'
    ;

2 个答案:

答案 0 :(得分:3)

试试这个:

STRING
 : '"'                          // a opening quote
   (                            // start group
     '\\' ~('\r' | '\n')        // an escaped char other than a line break char
     |                          // OR
     ~('\\' | '"'| '\r' | '\n') // any char other than '"', '\' and line breaks
   )*                           // end group and repeat zero or more times
   '"'                          // the closing quote
 ;

当我从您的评论中测试4个不同的测试用例时:

"\"hello\""
"ref(\"hello\",\"hello\")"
"\"h\"e\"l\"l\"o\""
"ref(\"hello\", \"hel\"lo\")"

我建议使用词法分析器规则:

grammar T;

parse
 : string+ EOF
 ;

string
 : STRING
 ;

STRING
 : '"' ('\\' ~('\r' | '\n') | ~('\\' | '"'| '\r' | '\n'))* '"'
 ;

SPACE
 : (' ' | '\t' | '\r' | '\n')+ {skip();}    
 ;

ANTLRWorks的调试器生成以下解析树:

enter image description here

换句话说:它工作正常(在我的机器上:))。

编辑II

我还使用了你的语法(进行了一些小改动以使其与Java兼容),我将错误的STRING规则替换为我建议的规则:

oaExpression
   :        STRING+ EOF!
   //: exponentiationExpression EOF!
   ;

exponentiationExpression
    :       equalityExpression ( '^' equalityExpression )*
    ;

equalityExpression
    :       relationalExpression ( ( ('==' | '=' ) | ('!=' | '<>' ) ) relationalExpression )*
    ;

relationalExpression
    :       additiveExpression ( ( '>' | '>=' | '<' | '<=' ) additiveExpression )*
    ;

additiveExpression
    :       multiplicativeExpression ( ( '+' | '-' ) multiplicativeExpression )*
    ;

multiplicativeExpression
    :       primaryExpression ( ( '*' | '/' ) primaryExpression )*
    ;

primaryExpression
    :       '(' exponentiationExpression ')' | value | identifier (arguments )?
    ;

value
    :       STRING
    ;

identifier
    :       ID
    ;

expressionList
    :       exponentiationExpression ( ',' exponentiationExpression )*
    ;

arguments
    :       '(' ( expressionList )? ')'
    ;                      

/*
 * Lexer rules
 */

ID
    :       LETTER (LETTER | DIGIT)*
    ;

//STRING
//    :       '"' ( options { greedy=false; } : ~'"' )* '"'
//    ;
STRING
    :       '"' ('\\' ~('\r' | '\n') | ~('\\' | '"'| '\r' | '\n'))* '"'
    ;

WS
    :       (' '|'\r'|'\t'|'\u000C'|'\n') {$channel=HIDDEN;} /*{$channel=Hidden;}*/
    ;

/*
 * Fragment Lexer rules
 */

fragment
LETTER
    :       'a'..'z'
    |       'A'..'Z'
    |       '_'
    ;

fragment
EXPONENT
    :       ('e'|'E') ('+'|'-')? ( DIGIT )+
    ;

fragment
HEX_DIGIT
    :       ( DIGIT |'a'..'f'|'A'..'F')
    ;

fragment
DIGIT
    :       '0'..'9'
    ;

在同一个解析树中解析前一个例子的输入。

答案 1 :(得分:0)

这是我使用包含转义序列的字符串(不仅仅是“但是任何”)的方法:

DOUBLE_QUOTED_TEXT
@init { int escape_count = 0; }:
    DOUBLE_QUOTE
    (
        DOUBLE_QUOTE DOUBLE_QUOTE { escape_count++; }
        | ESCAPE_OPERATOR .  { escape_count++; }
        | ~(DOUBLE_QUOTE | ESCAPE_OPERATOR)
    )*
    DOUBLE_QUOTE
    { EMIT(); LTOKEN->user1 = escape_count; }
;

该规则还会对转义进行计数并将其存储在令牌中。这允许接收器快速查看是否需要对字符串做任何事情(如果user1> 0)。如果您不需要删除@init部分和操作。