书看了大半,天马行空似懂非懂。返回头看看感觉没学到什么东西,所以还是动手尝试下。实际这个解析器只是sqlite语法的一个create table语法,而且也没完全实现(不支持check约束和指定数据库)。
为了定一个模子我先写了一个create table 的antlr文法(如下)照着做的。
grammarsqlitcreatetable; @members{ privatebooleanisType(Stringid){ id=id.toLowerCase(); returnid.equals("int")||id.equals("integer") ||id.equals("bool")||id.equals("boolean") ||id.equals("long") ||id.equals("short")||id.equals("byte") ||id.equals("float") ||id.equals("real")||id.equals("double") ||id.equals("blob") ||id.equals("text")||id.equals("varchar")||id.equals("nvarchar")||id.equals("string")||id.equals("char"); } } createTableStatment : 'create'(temp='temp'|temp='temporary')?'table'('if''not''exists')? name columnList';'? { System.out.print(($temp.text!=null?"temporary":"")+"table:"+$name.text); } ; columnList : '('column(','column)*')' ; column : name typetypelimit? constainst* { System.out.println("column:"+$name.text+""+$type.text); } ; typelimit : '('a=INT(','b=INT)?')' { if($a.text!=null&&$b.text!=null){ System.out.print("("+$a.text+","+$b.text+")"); }elseif($a.text!=null){ System.out.print("("+$a.text+")"); } } ; type : {isType(input.LT(1).getText())}?ID ; constainst : 'primary''key' {System.out.print("primarykey");} | 'unique' {System.out.print("unique");} | 'default''('(v=INT|v=FLOAT|v=STRING)')' {System.out.print("default("+$v.text+")");} | 'not''null' {System.out.print("notnull");} | 'autoincrement'{System.out.print("autoincrement");} ; name : '['ID']' | ID ; ID: ('a'..'z'|'A'..'Z'|'_')('a'..'z'|'A'..'Z'|'0'..'9'|'_')* ; INT: '0'..'9'+ ; FLOAT :('0'..'9')+'.'('0'..'9')*EXPONENT? |'.'('0'..'9')+EXPONENT? |('0'..'9')+EXPONENT ; COMMENT :'--'~('\n'|'\r')*'\r'?'\n'{$channel=HIDDEN;} |'/*'(options{greedy=false;}:.)*'*/'{$channel=HIDDEN;} ; STRING :'\''(ESC_SEQ|~('\\'|'\''))*'\'' ; fragment EXPONENT:('e'|'E')('+'|'-')?('0'..'9')+; fragment HEX_DIGIT:('0'..'9'|'a'..'f'|'A'..'F'); fragment ESC_SEQ :'\\'('b'|'t'|'n'|'f'|'r'|'\"'|'\''|'\\') |UNICODE_ESC |OCTAL_ESC ; fragment OCTAL_ESC :'\\'('0'..'3')('0'..'7')('0'..'7') |'\\'('0'..'7')('0'..'7') |'\\'('0'..'7') ; fragment UNICODE_ESC :'\\''u'HEX_DIGITHEX_DIGITHEX_DIGITHEX_DIGIT ; WS:('' |'\t' |'\r' |'\n' ){$channel=HIDDEN;} ;
生成这个文法的代码调试输入create table 语句则会输出表、列、列类型和约束信息。
sqlite的create table 语法还是比较简单的,用LL(1)即可以实现了。比较麻烦的还是词法分析部分,由于 Terence Parr讲解的例子里面未涉及到关键字的识别,所以对于关键字的识别我采用了向前看(n+1)来判断是否为某关键字。这个算法(isKW函数)或许是错误的方法请各位有经验的朋友指教。
代码没神码好贴的了有兴趣的朋友下载代码编译跑跑。看看输入内容
"createtemporarytable\n/*MLComment*/IFNOTEXISTS[table_name](\n[a1]intuniquenotnull,b1double(22)primarykey,c1string(1,2)AUTOINCREMENT,e1floatnotnull,ffchardefault(0.123))--SLComment";
在节点的保存上我采用了简单的收集需要的节点,而不是异形树或同型树之类,遍历的结果将输出这样的
MLComment SLComment tbl--temporaraytable_name Column--a1intuniquenotnull Column--b1double(22)primarykey Column--c1string(1,2)autoincrement Column--e1floatnotnull Column--ffstringdefault(0.123)
demo下载