练手写了个SQLite解析器

前端之家收集整理的这篇文章主要介绍了练手写了个SQLite解析器前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

书看了大半,天马行空似懂非懂。返回头看看感觉没学到什么东西,所以还是动手尝试下。实际这个解析器只是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下载

猜你在找的Sqlite相关文章