《ANTLR 4权威指南》笔记6 - 探索真实的语法
CSV⌗
grammar CSV;
file: hdr row+ ;
hdr : row ;
用一条额外的规则hdr
表示文件头,虽然规则只是row
,但可以把文件头更清楚地区分出来。
row: field (',' field)* '\r'? '\n';
field
: TEXT
| STRING
|
;
TEXT : ~[,\n\r"]+ ;
STRING : '"' ('""'|~'"')* '"' ; // 字符串中两个双引号是转义字符,表示一个双引号字符,注意这里一定要贪心策略
其中:
'\r'? '\n'
表示换行。
field
支持文本、字符串、空。
~[,\n\r]+
表示非方括号中的字符,出现1次或更多,~
表示非。
STRING
表示双引号包裹的0个或更多字符,中间出现的双引号需要转义,必须要贪心策略,否则无法匹配"x""y"
这样的字符串。
JSON⌗
ANTLR语法规则:
object
: '{' pair (',' pair)* '}'
| '{' '}' // empty object
;
pair: STRING ':' value ;
JSON标准参考:
object
{}
{ members }
members
pair
pair , members
pair
string : value
可以看到JSON标准用了members
规则,并且是尾递归,因为遵守BNF范式,没有*
循环结构,用尾递归代替。而ANTLR支持EBNF范式,有循环结构。
JSON有嵌套结构,所以是非直接递归的:
value
: STRING
| NUMBER
| object // 非直接递归
| array // 非直接递归
| 'true'
| 'false'
| 'null'
;
STRING
需要处理Unicode和转义。
NUMBER
和其他语言差不多。
DOT⌗
HTML String
HTML_STRING : '<' (TAG|~[<>])* '>' ;
fragment
TAG : '<' .*? '>' ;
单行注释#
开头
PREPROC : '#' .*? '\n' -> skip ;
Cymbol⌗
expr: ID '(' exprList? ')' // func call like f(), f(x), f(1,2)
| expr '[' expr ']' // array index like a[i], a[i][j]
| '-' expr // unary minus
| '!' expr // boolean not
| expr '*' expr
| expr ('+'|'-') expr
| expr '==' expr // equality comparison (lowest priority op)
| ID // variable reference
| INT
| '(' expr ')'
;
exprList : expr (',' expr)* ; // arg list
通常按照优先级列出可选规则。