The Definitive Antlr 4 第5章学习笔记

来源:互联网 发布:男烟女烟区别知乎 编辑:程序博客网 时间:2024/05/13 20:16

 The Definitive Antlr 4 Reference 2nd Edition  第5章学习笔记


antlr中所生成的parser用来处理token stream 而lexer用来处理char stream。Antlr中,文法与词法有类似的结构,因此可以将二者写在一个文件中。但词法分析与语法分析属于不同的阶段,所以需要告诉Antlr什么阶段进行语法分析,什么阶段进行词法分析。因此以大写字母开头的表示词法分析规则,以小写字母开头的表示语法分析规则。

例如下面定义了函数调用的语法与词法规则。

call : ID LP exprList RP ;LP : '(' ;RP : ')' ;
下面是本章的一些语法与词法定义的案例。

匹配字符串

这里字符串是由双引号""包含的字符序列,例如STRING:"...",对应文法可以写为 ".*?"。.匹配任意单个字符,在Antlr中支持非贪婪匹配,即满足条件的最小匹配。使用?为后缀,表示非贪婪匹配。.*贪婪匹配,加上后缀.*?表示非贪婪匹配".*?" 模式处理的字符串,不允许在字符串内部有双引号,为支持引号,需要使用转义符,文法如下:

expr : STRING;STRING: '"' (ESC|.)*? '"';fragmentESC : '\\"' | '\\\\';

由于转意符本身需要转意 因此使用 \\,当遇到未转义的"号,则字符串匹配结束。



匹配注释与空白符

在有些应用中,需要匹配空白符或删除空白符。如在赋值表达式中, a =     789;     = 号两侧是可以有若干的空格存在。

当希望丢弃匹配到的空白符,可以使用skip命令。

LINE_COMMENT : '//' .*? '\r'? '\n' -> skip ; 忽略单行注释。COMMENT : '/*' .*? '*/' -> skip ; 多行注释会被忽略



常用的词法定义

标示符定义:以C语言为例,C中变量标示符以字母下划线开头,随后可以跟若干个字母数字下划线。

expr :  ID;ID : ID_LETTER (ID_LETTER | DIGIT)*;fragment ID_LETTER: [a-zA-Z_];fragment DIGIT : [0-9];


数字定义: 通常有整数与浮点数的定义。

INT :  DIGIT+ ;FLOAT: DIGIT+ '.' DIGIT*      | '.' DIGIT+      ;

字符串定义:由双引号包围的字符串定义。

STRING :'"' ( ESC | . )*? '"' ;fragment ESC :'\\' [btnr"\\] ; // \b, \t, \n etc...



注释的定义:  匹配并丢弃注释

LINE_COMMENT : '//' .*? '\n' -> skip ;COMMENT : '/*' .*? '*/' -> skip ;

空白符号的定义:

由回车、换行、制表符构成。

WS : [ \t\n\r]+ -> skip ;

调用语句定义:

call : ID'('exprList')';exprList : | ID (','ID)*;ID : ID_LETTER (ID_LETTER | DIGIT)*;WS : [ \t\n\r]+->skip;fragment ID_LETTER: [a-zA-Z_];fragment DIGIT : [0-9];<strong>



词法分析与语法分析器的关联

由于在Antlr中词法规则可以使用递归定义,词法与语法规则定义同样强大。这样,在词法定义中甚至可以匹配程序结构。相反,也可以将语法分析中的符号元素看作是字符的集合,然后对这些字符进行语法分析。


下面是一些使用Antlr的一些经验:

  • 由于在语法分析中某些符号并不需要,因此在词法分析中匹配并丢弃这些符号。例如注释空白符等。
  • 通过词法分析来匹配符号,如标示符,关键字,字符串,数字等。因为语法分析的开销比词法分析更大,因此不应该让语法分析器来完成词法分析任务。
  • 将词法分析器所处理的元素当作一个整体来对待。例如,词法分析并不关系XML标签的内容,因此词法分析器可以将<>内的元素看做一个整体识别,并作为Tag(标签)来对待。

此外,如果是语法分析器需要处理的元素,那么词法分析器应该将这些元素单独传给语法分析器。例如分析IP地址,那么IP地址中的数字与符号(.)应该单独作为词法单元,最后传给语法分析器。


有时候语法分析并不需要分析某些结构,例如一个日志文件中 

192.168.209.85"GET /download/foo.html HTTP/1.0" 200 

这样的数据有多少行。由于仅仅是分析有多少行,因此仅需要考虑\n 换行符号,其它元素可以直接忽略掉。

因此这样的一个文件的文法可以是:

file : NL+ ;STUFF : ~'\n'+-> skip ; // 除了换行以外的字符全部忽略NL : '\n' ; // 换行符号的定义

~x 意思是匹配除了x以外的所有字符。



0 0
原创粉丝点击