objective-c - ParseKit - SQLite 解析器进入无限递归

标签 objective-c sql sqlite parsekit

对于我的应用程序,我正在尝试构建 SQLite解析器。由于我的应用程序使用的是 Objective-C,ParseKit似乎是一个不错的选择。我读了 SQLite 的 syntax diagrams并基于它们建立了语法。但是,当我尝试使用此语法解析某些内容时,解析器会进入无限递归。

我需要的唯一语句是 SELECT、INSERT、UPDATE 和 DELETE(我需要 SELECT 主要是因为其他语句引用它)。我的 @start 旨在处理用分号分隔的多个语句:

@start = statement (';' statement)*;

statement = select_stmt | insert_stmt | update_stmt | delete_stmt ;

声明如下:

select_stmt = select_core ( compound_operator select_core )* order_expr? limit_expr? ;
select_core = 'select' ( 'distinct' | 'all' )? result_column ( ',' result_column )* from_expr where_expr group_expr ;
result_column = '*' | table_name '.' '*' | expr ( 'as'? column_alias )? ;

insert_stmt = 'insert' or_on_failure? 'into' table_name insert_expr ;
insert_expr = insert_expr_cols? (insert_expr_values | select_stmt) ;
insert_expr_cols = '(' column_name ( ',' column_name )* ')' ;
insert_expr_values = 'values' '(' expr ( ',' expr )* ')' ;
insert_expr_defaults = 'default' 'values' ;

update_stmt = 'update' or_on_failure? qualified_table_name update_expr where_expr? limited_expr? ;
update_expr = 'set' update_expr_col ( ',' update_expr_col )* ;
update_expr_col = column_name '=' expr ;

delete_stmt = 'delete' 'from' qualified_table_name where_expr? limited_expr? ;

及其支持表达式:

order_expr = 'order' 'by' ordering_term (',' ordering_term)* ;
limit_expr = 'limit' expr ( ( 'offset' | ',' ) expr )? ;
from_expr = 'from' join_source ;
where_expr = 'where' expr ;
group_expr = 'group' 'by' expr ( ',' expr )? ( 'having' expr )? ;

join_source = single_source ( join_operator single_source join_constraint? )* ;
single_source = table_name 'as' table_alias indexed_by? | '(' select_stmt ')' ( 'as'? table_alias )? | '(' join_source ')' ;

or_on_failure = 'or' on_failure ;
on_failure = 'rollback' | 'abort' | 'replace' | 'fail' | 'ignore' ;
limited_expr = order_expr limit_expr ;

姓名、别名:

database_name = name ;
table_name = (database_name '.')? name ;
column_name = (table_name '.')? name ;

table_alias = name ;
column_alias = name ;

index_name = name ;

type_name = name+ ( '(' number (',' number)? ')' )? ;
function_name = name ;
collation_name = name ;

qualified_table_name = table_name indexed_by? ;

其他运算符等:

indexed_by = 'indexed' 'by' index_name | 'not' 'indexed' ;

unary_operator = symbol ;
binary_operator = symbol ;
compound_operator = 'union' 'all'? | 'intersect' | 'except' ;
join_operator = ',' | 'natural'? ( 'left' 'outer'? | 'inner' | 'cross' ) 'join' ;

join_constraint = 'on' expr | 'using' '(' column_name ( ',' column_name )* ')' ;

基本类型:

literal = number
    | string
    | 'null'
    | 'current_time'
    | 'current_data'
    | 'current_timestamp' ;
number = Number ;
string = Word
    | QuotedString ;
name = Word
    | QuotedString ;
symbol = Symbol;

和 EXPR:

expr = literal
    | column_name
    | unary_operator expr
    | expr binary_operator expr
    | function_name '(' ( '*' | 'distinct'? expr ( ',' expr )* )? ')'
    | '(' expr ')'
    | 'cast' '(' expr 'as' type_name ')'
    | expr 'collate' collation_name
    | expr 'not'? ( 'like' | 'glob' | 'regexp' | 'match' ) expr ( 'escape' expr )?
    | expr ( 'isnull' | 'notnull' | 'not' 'null' )
    | expr 'is' 'not'? expr
    | expr 'not'? 'between' expr 'and' expr
    | expr 'not'? 'in' ( table_name | '(' ( select_stmt | expr ( ',' expr )* )? ')' )
    | ( 'not'? 'exists' )? '(' select_stmt ')'
    | 'case' expr? ( 'when' expr 'then' expr )+ ( 'else' expr )? 'end' ;

当我单步执行代码时,基本路径是@start -> statements -> select_stmt -> select_core -> result_column -> expr -> expr -> expr...

在 PKParser 的 matchAndAssemble: 和 PKParser/Subclass 的 allMatchesFor: 之间进行大约 8-9k 次调用后,某些东西会死掉,通常是由于 EXC_BAD_ACCESS 错误(然后 LLDB 也无法执行任何操作)。

P.S.:如果你要发布一个答案说:“哦,你真的应该这样做/使用这个”,A)我喜欢 Objective-C。不要告诉我不要使用它。这是我的选择。我的回应很可能是咆哮。 B) 我尝试挖掘 SQLite 的源代码来使用他们的解析器。我从来没有到过任何地方。如果您认为我应该使用它,请将其解析器的源代码作为没有其他依赖项的单个文件发布。

最佳答案

ParseKit 的开发者这里。

首先,请参阅我之前在 debugging ParseKit grammars 上的回答和 battling infinite recursion in ParseKit grammars .


我认为第一行可能有问题(但我不是 SQL 专家,所以我不确定)。难道不应该是:

@start = (statement ';')+;

我强烈建议使用驼峰式大小写而不是下划线,因为下划线会让你的 Objective-C 回调变得非常尴尬和丑陋。这就是为什么驼峰大小写是 ParseKit 语法中的约定。


但是,我看到了主要问题。您的语法包含 ParseKit 语法中不允许的左递归。特别是在您的 expr 生产中(我没有仔细查看它是否也在其他地方)。

ParseKit 可以使用递归,但不能使用左递归。对此最好的解释在 Steven Metsker's "Building Parsers with Java" 。或search the web .

但基本上左递归是指产生式立即引用自身(在表达式的左侧):

e = e '-' Number;

e = Number | e '-' Number;

相反,您必须设计语法来删除左递归,例如:

e = Number ('-' Number)*;

关于objective-c - ParseKit - SQLite 解析器进入无限递归,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14597299/

相关文章:

ios - 使用 NSDictionary 作为其他 NSDictionary 的键

ios - 获取格式化日期为 NSDate

objective-c - Objective C 中的继承

android - 如何在android sqlite 'execSQL'语句中设置一个整数和一个字符串值

ios - 背景 NSManagedObjectContext 的更改在 Main 上不可见,使用 NSFetchedResultsController

python - 在 Python 3.3 中使用 %s 的 SQL 查询

sql - Oracle 11g 上的 select 子句中的双/随机别名不会引发无效标识符异常

sql - 左加入和分组依据

python - 我可以从 South 生成适用于不同数据库 [sqlite 和 postgresql] 的模式迁移吗?

c# - 如何安全地重命名 Xamarin.Forms 中表示 SQLite 实体的类的属性?