[英]Custom objects in ParseKit Actions
能夠向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')
以便我可以設置該值。 這些令牌在堆棧上嗎? 有沒有比彈出“創建”更好的方法,看看我們是否通過了它。 每次比賽我都應該回到堆棧底部嗎?
另外,如果我的規則是
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,但是它的細微差別確實會給您帶來麻煩。
這里是ParseKit的創建者。 一些項目:
就在本周,我將ParseKit分叉到了一個更清潔/更小/更快的名為PEGKit的庫中。 不應考慮使用ParseKit,而應將PEGKit用於所有新開發。 請移至PEGKit。
PEGKit與ParseKit的語法和代碼生成功能幾乎相同 ,並且您的ParseKit語法可與PEGKit一起使用,但有一些小的變化。 實際上,您在此問題中的所有示例都可以使用,而PEGKit中沒有任何更改。
我在上面的語法樣本中發現了3個語法錯誤(這同樣適用於ParseKit和PEGKit)。
這行:
createTableStmt ='CREATE'('TEMP'|'TEMPORARY')? '表''如果不存在'? 數據庫名稱;
應該:
createTableStmt ='CREATE'('TEMP'|'TEMPORARY')? 'TABLE'('IF''NOT''EXISTS')? 數據庫名稱;
注意將無效的'IF NOT EXISTS'
構造分解為單個文字標記。 這不僅是必要的,而且也是可取的,以便允許單詞之間的可變空格。
POP()
宏應全部為大寫 。
您的createTableStmt
規則在最后(操作結束}
之后缺少分號)。
確保您使用的是v0.3.1 PEGKit或更高版本(master的HEAD)。 我在找到問題的答案時修正了一個重要的錯誤,下面的解決方案也需要此修正。
我的問題是如何查看它是否匹配('TEMP'|'TEMPORARY'),以便設置該值?
好問題! 在上面的進一步評論中,您基本上有正確的想法。
具體來說,我可能會將createTableStmt
規則分解為以下4條規則:
createTableStmt = 'CREATE'! tempOpt 'TABLE'! existsOpt databaseName ';'!;
databaseName = QuotedString;
tempOpt
= ('TEMP'! | 'TEMPORARY'!)
| Empty
;
existsOpt
= ('IF'! 'NOT'! 'EXISTS'!)
| Empty
;
注意所有至關重要的!
丟棄偽指令,用於丟棄不需要的文字令牌。
另請注意,我已將最后兩個規則更改為使用| Empty
| Empty
而不是?
。 這樣一來,我便可以將Actions添加到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); }
;
至於您的第二個問題,請將其作為一個新的SO問題進行分解,並將其標記為ParseKit
和PEGKit
,我將盡快解決。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.