簡體   English   中英

ParseKit操作中的自定義對象

[英]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棄用:

就在本周,我將ParseKit分叉到了一個更清潔/更小/更快的名為PEGKit的庫中。 不應考慮使用ParseKit,而應將PEGKit用於所有新開發。 請移至PEGKit。

PEGKit與ParseKit的語法和代碼生成功能幾乎相同 ,並且您的ParseKit語法可與PEGKit一起使用,但有一些小的變化。 實際上,您在此問題中的所有示例都可以使用,而PEGKit中沒有任何更改。

請參閱ParseKit自述文件中的棄用聲明

還有關於PEGKit的教程

語法錯誤:

我在上面的語法樣本中發現了3個語法錯誤(這同樣適用於ParseKit和PEGKit)。

  1. 這行:

      createTableStmt ='CREATE'('TEMP'|'TEMPORARY')?  '表''如果不存在'?  數據庫名稱; 

    應該:

      createTableStmt ='CREATE'('TEMP'|'TEMPORARY')?  'TABLE'('IF''NOT''EXISTS')?  數據庫名稱; 

    注意將無效的'IF NOT EXISTS'構造分解為單個文字標記。 這不僅是必要的,而且也是可取的,以便允許單詞之間的可變空格。

  2. POP()宏應全部為大寫

  3. 您的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); }
    ;

我已經將此語法和一個測試用例添加到PEGKit項目中

至於您的第二個問題,請將其作為一個新的SO問題進行分解,並將其標記為ParseKitPEGKit ,我將盡快解決。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM