ParseKit操作中的自定义对象 [英] Custom objects in ParseKit Actions

查看:104
本文介绍了ParseKit操作中的自定义对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对将动作添加到ParseKit语法的能力非常着迷.令人惊讶的是,很少有文档说明这些操作中可用的内容.假设我有两个规则,例如:

I am very intrigued by the ability to add actions to ParseKit grammars. There is surprisingly little documentation on what is available in those actions. Say I have two rules like:

databaseName        = Word;
createTableStmt     ='CREATE' ('TEMP'| 'TEMPORARY')? 'TABLE' 'IF NOT EXISTS'? databaseName;

这显然不是一个完整的语法,但将作为一个例子.解析时,我想返回"具有某些属性的CreateTableStmt对象.如果我正确地理解了该工具,我会在规则中添加一个动作,先做一些事情,然后将其推入装配中,以便随身携带以供下一个要处理或使用的规则.

This obviously isn't a whole grammar but will serve as an example. When parsing i'd like to "return" a CreateTableStmt object that has certain properties. If I understand the tool correctly i'd add an action to the rule, do stuff then push it on the assembly which will carry it around for the next rule to deal with or use.

例如,它看起来像:

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.然后,与使用传入的字符串相比,我可以更轻松地完成具有这种表示形式的事情.

Then when everything is parsed I can just get that root object off the stack and it is a fully instantiated custom representation of the grammar. Somewhat like building an AST if i remember correctly. I can then do stuff with that representation much easier than with the passed in string.

我的问题是如何查看它是否匹配('TEMP' | 'TEMPORARY'),所以我可以设置该值.这些令牌在堆栈上吗?有没有比弹出创建"更好的方法,看看我们是否通过了它.每次比赛我都应该回到堆栈底部吗?

My question is how can I see if it matched ('TEMP' | 'TEMPORARY') so I can set the value. Are those tokens on the stack? Is there a better way than to pop back to the 'CREATE' and see if we passed it. Should I be popping back to the bottom of the stack anyway on each match?

如果我的规则改为

qualifiedTableName  = (databaseName '.')? tableName (('INDEXED' 'BY' indexName) | ('NOT' 'INDEXED'))?;

假设在匹配规则之前不会调用该操作是否正确?因此,在这种情况下,当操作被调用到堆栈时,可能看起来像这样:

Is it correct to assume that the action would not be called until the rule had been matched? So in this case when the action is called to the stack could look like:

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,但它的细微差别确实会给您带来麻烦.

Are these correct assessments? Is there any other documentation on actions? I know it is heavily based on Antlr but its the subtle differences that can really get you in trouble.

推荐答案

此处 ParseKit 的创建者.一些项目:

Creator of ParseKit here. A few items:

就在本周,我将ParseKit分叉到了一个更干净/更小/更快的库中,该库名为 PEGKit .应该认为ParseKit已过时,而PEGKit应该用于所有新开发.请移至PEGKit.

Just this week, I have forked ParseKit to a cleaner/smaller/faster library called PEGKit. ParseKit should be considered deprecated, and PEGKit should be used for all new development. Please move to PEGKit.

PEGKit与ParseKit的语法和代码生成功能几乎相同,并且您的ParseKit语法可在PEGKit中使用,但有一些小的更改.实际上,您在此问题中的所有示例都可以使用,而PEGKit中没有任何更改.

PEGKit is nearly identical to the grammar and code-gen features of ParseKit, and your ParseKit grammars are usable with PEGKit with a few small changes. In fact, all of the examples in your question here are usable with no changes in PEGKit.

请参阅ParseKit自述文件中的弃用声明.

PEGKit上的教程.

我在上面的语法样本中发现了3个语法错误(这同样适用于ParseKit和PEGKit).

I spot 3 syntax errors in your grammar samples above (this applies equally to both ParseKit and PEGKit).

  1. 此行:

  1. This line:

createTableStmt     ='CREATE' ('TEMP'| 'TEMPORARY')? 'TABLE' 'IF NOT EXISTS'? databaseName;

应该是:

createTableStmt     ='CREATE' ('TEMP'| 'TEMPORARY')? 'TABLE' ('IF' 'NOT' 'EXISTS')? databaseName;

请注意将无效的'IF NOT EXISTS'构造分解为单独的文字标记.这不仅是必要的,而且也是可取的,以便允许单词之间的可变空格.

Notice the break up of the invalid 'IF NOT EXISTS' construct into individual literal tokens. This is not only necessary, but also desireable so that variable whitespace between the words is allowed.

POP()宏应为所有大写字母.

您的createTableStmt规则在最后(操作结束}之后)缺少分号.

Your createTableStmt rule is missing a semicolon at the very end (after the action's closing }).

在回答之前:

确保您使用的是 v0.3.1 PEGKit 或更高版本(主人的头).在解决您的问题的答案时,我修复了一个重要的错误,以下我的解决方案也需要此修复程序.

Before Answering:

Make sure you are using v0.3.1 PEGKit or later (HEAD of master). I fixed an important bug while finding the answer to your question, and my solutions below require this fix.

我的问题是如何查看它是否匹配('TEMP'|'TEMPORARY'),以便我可以设置该值?

My question is how can I see if it matched ('TEMP' | 'TEMPORARY') so I can set the value?

好问题!在上面的进一步评论中,您基本上有一个正确的想法.

Good question! You basically have the right idea in your further comments above.

具体地说,我可能会将createTableStmt规则分解为4条规则,如下所示:

Specficially, I would probably break up the createTableStmt rule into 4 rules like this:

createTableStmt = 'CREATE'! tempOpt 'TABLE'! existsOpt databaseName ';'!;

databaseName = QuotedString;

tempOpt 
    = ('TEMP'! | 'TEMPORARY'!)
    | Empty
    ;

existsOpt 
    = ('IF'! 'NOT'! 'EXISTS'!)
    | Empty
    ;

  • 请注意所有重要的!丢弃指令,用于丢弃不需要的文字令牌.

    • Notice all of the vital ! discard directives for discarding unneeded literal tokens.

      也请注意,我将最后两个规则更改为使用| Empty而不是?.这样一来,我便可以将Actions添加到Empty选项(您将在几秒钟内看到它).

      Also Notice that I've changed the last two rules to use | Empty rather than ?. This is so I can add Actions to the Empty alternatives (you'll see that in a sec).

      然后,您可以将动作添加到语法中,或者,如果您希望使用纯代码,则可以使用ObjC 解析器委托回调.

      Then you can either add Actions to your grammar, or use ObjC parser delegate callbacks if you prefer to work in pure code.

      如果您在语法中使用动作,则类似以下的内容将起作用:

      If you use Actions in your grammar, something like the following will work:

      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,我会尽快解决.

      As for your second question, please break it out as a new SO question, and tag it ParseKit and PEGKit and I will get to it ASAP.

      这篇关于ParseKit操作中的自定义对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆