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

通常按照优先级列出可选规则。

R