2013-05-13 44 views
1

我想为某种语言编写ANTLR4词法分析器。我有一个工作,但我不完全满意。ANTLR4令牌图像连接与混合中的注释

keyword "my:little:uri" + /* my comment here */ ':it:is' 
// nasty comment 
+ ":mehmeh"; // single line comment 

keyword + {} 

这是语言语句的一个例子。它只是一串关键字后跟字符串参数,并以分号或子语句块结尾。字符串可能不加引号,单引号或双引号。引用的字符串可以像上面的例子那样连接起来。包含加号(+)的未加引号的字符串是有效的。

我觉得有问题的是评论。我想识别关键字作为单个字符串标记之后的任何内容,而不是注释(和空格)。我通常使用more词法分析器命令,但我认为它不适用于上述示例。有没有一种模式可以让我实现这样的目标?

我现在的词法语法:

lexer grammar test; 

@members { 
    public static final int CHANNEL_COMMENTS = 1; 
} 

WHITESPACE : (' ' | '\t' | '\n' | '\r' | '\f') -> skip; 

SINGLE_LINE_COMMENT : '//' (~[\n\r])* ('\n' | '\r' | '\r\n')? -> channel(CHANNEL_COMMENTS); 

MULTI_LINE_COMMENT : '/*' .*? '*/' -> channel(CHANNEL_COMMENTS); 

KEYWORD : 'keyword' -> pushMode(IN_STRING_KEYWORD); 

LBRACE : '{'; 
RBRACE : '}'; 
SEMICOLON : ';'; 

mode IN_STRING_KEYWORD; 
STRING_WHITESPACE : WHITESPACE -> skip; 
STRING_SINGLE_LINE_COMMENT : SINGLE_LINE_COMMENT -> type(SINGLE_LINE_COMMENT), channel(CHANNEL_COMMENTS); 
STRING_MULTI_LINE_COMMENT : MULTI_LINE_COMMENT -> type(MULTI_LINE_COMMENT), channel(CHANNEL_COMMENTS); 
STRING_LBRACE : LBRACE -> type(LBRACE), popMode; 
STRING_SEMICOLON : SEMICOLON -> type(SEMICOLON), popMode; 
STRING : ((QUOTED_STRING ('+' QUOTED_STRING)*) | UNQUOTED_STRING); 
fragment QUOTED_STRING : (SINGLEQUOTED_STRING | DOUBLEQUOTED_STRING); 
fragment UNQUOTED_STRING : (~[ \t;{}/*'"\n\r] | '/' ~[/*] | '*' ~['/'])+; 
fragment SINGLEQUOTED_STRING : '\'' (~['])* '\''; 
fragment DOUBLEQUOTED_STRING : 
    '"' 
     (
     (~["\\]) | 
     ('\\' [nt"\\]) 
    )* 
    '"' 
; 

难道我也许想要做的词法分析器里面太多,应该只给我目前有解析器,让它处理上述烂摊子?

Edit01

感谢280Z28,我决定摆脱修复以上词法语法我STRING令牌和简单地满足于QUOTED_STRINGUNQUOTED_STRING和运营商CONCAT。其余的部分将在解析器中处理。为了区分CONCATUNQUOTED_STRING,我还添加了额外的词法分析器模式。

lexer grammar test; 

@members { 
    public static final int CHANNEL_COMMENTS = 2; 
} 

WHITESPACE : (' ' | '\t' | '\n' | '\r' | '\f') -> skip; 
SINGLE_LINE_COMMENT : '//' (~[\n\r])* -> channel(CHANNEL_COMMENTS); 
MULTI_LINE_COMMENT : '/*' .*? '*/' -> channel(CHANNEL_COMMENTS); 

KEYWORD : 'keyword' -> pushMode(IN_STRING_KEYWORD); 

LBRACE : '{'; 
RBRACE : '}'; 
SEMICOLON : ';'; 

mode IN_STRING_KEYWORD; 
STRING_WHITESPACE : WHITESPACE -> skip; 
STRING_SINGLE_LINE_COMMENT : SINGLE_LINE_COMMENT -> type(SINGLE_LINE_COMMENT), channel(CHANNEL_COMMENTS); 
STRING_MULTI_LINE_COMMENT : MULTI_LINE_COMMENT -> type(MULTI_LINE_COMMENT), channel(CHANNEL_COMMENTS); 
STRING_LBRACE : LBRACE -> type(LBRACE), popMode; 
STRING_SEMICOLON : SEMICOLON -> type(SEMICOLON), popMode; 
QUOTED_STRING : (SINGLEQUOTED_STRING | DOUBLEQUOTED_STRING) -> mode(IN_QUOTED_STRING); 
UNQUOTED_STRING : (~[ \t;{}/*'"\n\r] | '/' ~[/*] | '*' ~[/])+; 
fragment SINGLEQUOTED_STRING : '\'' (~['])* '\''; 
fragment DOUBLEQUOTED_STRING : 
    '"' 
     (
     (~["\\]) | 
     ('\\' [nt"\\]) 
    )* 
    '"' 
; 

mode IN_QUOTED_STRING; 
QUOTED_STRING_WHITESPACE : WHITESPACE -> skip; 
QUOTED_STRING_SINGLE_LINE_COMMENT : SINGLE_LINE_COMMENT -> type(SINGLE_LINE_COMMENT), channel(CHANNEL_COMMENTS); 
QUOTED_STRING_MULTI_LINE_COMMENT : MULTI_LINE_COMMENT -> type(MULTI_LINE_COMMENT), channel(CHANNEL_COMMENTS); 
QUOTED_STRING_LBRACE : LBRACE -> type(LBRACE), popMode; 
QUOTED_STRING_SEMICOLON : SEMICOLON -> type(SEMICOLON), popMode; 
QUOTED_STRING2 : QUOTED_STRING -> type(QUOTED_STRING); 
CONCAT : '+'; 
+0

你应该在你的问题中包含每种字符串的确切语义(特别是未加引号的字符串)。 – 2013-05-13 13:28:57

+0

@ 280Z28,这可以从我的语法中看出来。还是你的意思是人类可读的形式? – predi 2013-05-13 13:33:01

+0

问题是,如果你的语法工作正常,你不需要问这个问题。包括一个单独的描述有助于澄清你正在尝试做什么,所以我可以将它与你实际做的相比较。 :) – 2013-05-13 13:42:05

回答

1
  • 不要在词法分析器执行字符串连接。作为运算符将+运算符发送到解析器。这将使得更容易消除字符串和操作员之间出现的空白和/或注释。

    CONCAT : '+'; 
    STRING : QUOTED_STRING | UNQUOTED_STRING; 
    
  • 你应该知道,ANTLR 4改变了预定义的HIDDEN通道99-1,所以HIDDENCHANNEL_COMMENTS是你的语法相同。

  • 请勿在SINGLE_LINE_COMMENT规则末尾包含行结束符。

    SINGLE_LINE_COMMENT 
        : '//' (~[\n\r])* 
         -> channel(CHANNEL_COMMENTS) 
        ; 
    
  • UNQUOTED_STRING令牌目前包含一组['/']。如果您打算排除'个字符,则该集合中的第二个'是多余的,因此您可以使用['/]。如果您只打算排除/,则可以使用语法[/]'/'

+0

我知道预定义的HIDDEN频道,但感谢您指出它。我的实际语法使用频道以外的常量。你对错误的“SINGLE_LINE_COMMENT”和“UNQUOTED_STRING”是正确的。 – predi 2013-05-13 13:54:21

+0

我想我对“在词法分析器中做得太多”的怀疑是正确的。如果它不在参考书中,它可能不存在。所以一旦我尝试了你的建议,我可能会接受这个答案。 – predi 2013-05-13 14:06:50

+0

亲爱的downvoter:请留下评论或我不能纠正问题:) – 2013-05-13 17:51:45