我对向ParseKit语法添加动作的能力非常感兴趣。关于这些行动中可用的内容的文件很少令人惊讶。说我有两个规则,如:
databaseName = Word;
createTableStmt ='CREATE' ('TEMP'| 'TEMPORARY')? 'TABLE' 'IF NOT EXISTS'? databaseName;
这显然不是一个完整的语法,而是作为一个例子。在解析时,我想“返回”具有某些属性的CreateTableStmt
对象。如果我正确理解了该工具,我会在规则中添加一个动作,然后将其推送到组件上,该组件将随身携带它以供下一个处理或使用的规则。
所以例如它看起来像:
createTableStmt ='CREATE' ('TEMP'| 'TEMPORARY')? 'TABLE' 'IF NOT EXISTS'? databaseName;
{
AnotherObj* dbName = Pop(); //gives me the top most object
CreateTableStmt* createTable = [[CreateTableStmt alloc] initWith:dbName];
//set if it was temporary
// set 'IF NOT EXISTS'
PUSH(createTable);//push back on stack for next rule to use
}
然后当解析所有内容时,我可以从堆栈中获取该根对象,它是一个完全实例化的语法自定义表示。如果我没记错的话,有点像建立一个AST。然后,我可以比使用传入的字符串更容易地使用该表示。
我的问题是如何查看它是否与('TEMP' | 'TEMPORARY')
匹配,以便我可以设置该值。这些令牌是否在堆栈中?有没有比回到'CREATE'更好的方法,看看我们是否通过了它。我是否应该在每场比赛中回弹到堆栈的底部?
另外,如果我的规则是
qualifiedTableName = (databaseName '.')? tableName (('INDEXED' 'BY' indexName) | ('NOT' 'INDEXED'))?;
假设在匹配规则之前不会调用操作是否正确?因此,在这种情况下,当向堆栈调用操作时可能如下所示:
possibly:
|'INDEXED'
|'NOT'
or:
|indexName (A custom object possibly)
|'BY'
|'INDEXED
|tableName (for sure will be here)
and possibly these
|'.' (if this is here I know the database name must be here) if not push last one on?
|databaseName
--------------(perhaps more things from other rules)
这些正确的评估吗?有关于行动的其他文件吗?我知道它主要基于Antlr,但其微妙的差异可以让你遇到麻烦。
答案 0 :(得分:4)
ParseKit的创作者。一些项目:
就在本周,我已将ParseKit分叉到一个名为PEGKit的更清洁/更小/更快的库中。 ParseKit应被视为已弃用,并且PEGKit应用于所有新开发。请转到PEGKit。
PEGKit几乎与ParseKit 的语法和代码生成功能相同,并且您的ParseKit语法可与PEGKit一起使用,只需进行一些小的更改。事实上,您的问题中的所有示例都可以使用而不会改变PEGKit。
See the Deprecation Notice in the ParseKit README
我在上面的语法示例中发现了3个语法错误(这同样适用于ParseKit和PEGKit)。
这一行:
createTableStmt ='CREATE' ('TEMP'| 'TEMPORARY')? 'TABLE' 'IF NOT EXISTS'? databaseName;
应该是:
createTableStmt ='CREATE' ('TEMP'| 'TEMPORARY')? 'TABLE' ('IF' 'NOT' 'EXISTS')? databaseName;
注意将无效'IF NOT EXISTS'
构造分解为单个文字标记。这不仅是必要的,而且也是可取的,因此允许在单词之间使用可变的空格。
POP()
宏应全部大写。
您的createTableStmt
规则最后缺少分号(在操作结束后}
)。
确保您使用的是v0.3.1 PEGKit或更高版本(HEAD of master)。我找到了一个重要的错误,同时找到了你的问题的答案,我的解决方案需要这个解决方案。
我的问题是如何才能看到它是否匹配('TEMP'|'TEMPORARY')所以我可以设置值?
好问题!您在上面的进一步评论中基本上都有正确的想法。
具体来说,我可能会将createTableStmt
规则分解为4条规则:
createTableStmt = 'CREATE'! tempOpt 'TABLE'! existsOpt databaseName ';'!;
databaseName = QuotedString;
tempOpt
= ('TEMP'! | 'TEMPORARY'!)
| Empty
;
existsOpt
= ('IF'! 'NOT'! 'EXISTS'!)
| Empty
;
请注意丢弃不需要的文字代币的所有重要!
丢弃指令。
另请注意,我已将最后两条规则更改为使用| Empty
而非?
。这样我就可以为空替代品添加动作(你会在一秒内看到)。
然后,您可以将操作添加到语法中,或者如果您更喜欢使用纯代码,则可以使用ObjC 解析器委托回调。
如果您在语法中使用操作,则以下内容将起作用:
createTableStmt = 'CREATE'! tempOpt 'TABLE'! existsOpt databaseName ';'!
{
NSString *dbName = POP();
BOOL ifNotExists = POP_BOOL();
BOOL isTemp = POP_BOOL();
NSLog(@"create table: %@, %d, %d", dbName, ifNotExists, isTemp);
// go to town
// myCreateTable(dbName, ifNotExists, isTemp);
};
databaseName = QuotedString
{
// pop the string value of the `PKToken` on the top of the stack
NSString *dbName = POP_STR();
// trim quotes
dbName = [dbName substringWithRange:NSMakeRange(1, [dbName length]-2)];
// leave it on the stack for later
PUSH(dbName);
};
tempOpt
= ('TEMP'! | 'TEMPORARY'!) { PUSH(@YES); }
| Empty { PUSH(@NO); }
;
existsOpt
= ('IF'! 'NOT'! 'EXISTS'!) { PUSH(@YES); }
| Empty { PUSH(@NO); }
;
我added this Grammar and a test case to the PEGKit project。
至于你的第二个问题,请将其作为一个新的SO问题进行分解,并将其标记为ParseKit
和PEGKit
,我会尽快找到它。