| ||||
| http://www.faqs.org/rfcs/rfc822.html 以上是RFC822 Internet Message的语法定义文件. 目前我采用Recursion Decsent的方法,完成了address和message的解析,但message目前的分析陷入一个困境:就是需要同时分析address和date-time.目前的做法可能是统一词法层和语法层,但这样做出的编码是hard coding,没有什么扩展性;如果其他人添加了新的rule,我就得改动代码,而且改动很大.我想问一下,针对RFC822 Message的分析,是不是有更好的解决方案,比如提供类似parserc的库,是否可行?主要RFC822的语法定义是采用的ABNF,语法中有大量的左递归和左因子. |
| ||||
| 我写过完整的body+header的parser,我觉得你说的有几个问题: 1.不存在不能区分body中的date time和header中的date time的问题。因为你应该对body进行另外处理。一上去就应该把body和header分开的 2.对于header中的东西,你应该一行一行的分析 3.关于错误检测,我写过类似的parser,不过是用在CASL汇编里面的,你必须在产生式里面把错误检测考虑进去。 4.我不觉得ATOM和DIGIT需要区分呀。因为通常你在上层的产生式里面就可以知道接下去需要的是ATOM还是DIGIT。而且我记得DIGIT仅用在仅有的一些和日期相关的地方。 5.左递归其实可以消除的 |
| ||||
| 引用:
2.不是,关键要弄清楚两点: 是否必要:因为大多数email是机器生成的,如果有错,报错就行了 确切定义:你要给你想recover的错误一个确切的定义,而不是简单的说recover,电脑很笨的 4.如果在词法层真得无法区分,那么就加一个新的TOKEN,叫ATOM_OR_DIGIT,然后把所有的ATOM和DIGIT放到这个里面去。在语法一层进一步检验是否正确 5. 我上班时候不用MSN的,何况我的MSN其实就在这个论坛里面 :P 只不过你没发现。我知道论坛的节奏比较慢,但是优点在于,大家可以分享,也比较持久。 |
| |||
| 代码:
但是没有看明白你说的问题在哪里。 至于左递归。你是不是指的这个"#"? 如果是这样, 很简单的。用jparsec的sepBy1组合子就可以了。 举个例子: 代码:
|
| |||
| 大致写了一个对应的parser。你看看合适不合适。 没有带语义动作,如果你需要创建ast, 可以做相应的修改。 代码:
|
| ||||
| 引用:
4. ATOM其实是包含DIGIT的,因为若干个数字既可以分析成ATOM也可以是DIGIT. 延迟选择是一种很好的方法,提取公共左因子就是这种思想的体现.目前我不打算在词法层分析出一个个的单独数字,我觉得没有必要了.我完全可以全部读到atom中,然后在分析date-time的时候进行检验. BTW,我目前所实现的address和date-time的parser都是单独的两个parser.其实最好的解决方案是能够兼容以后的扩展,如果以后加入新的ABNF rule的话,我的这个东东的结构要做比较大的改动,所以感觉有点像hard coding.所以,最终的方法是不是像Jparsec这样架构的东东比较好呢? 关于文档RFC822,我有一些疑问: a. header字段的每个field都是看作一个long string,但是可以folded,对吧;那么body字段呢,应当也是可以被folded的吧.似乎两者都应当处理multi-line的情况吧.目前address和date-time都是这么做的,\r\n后必然至少保证一个lwsp. b. 关于文档section 4 message specification部分,其实是包含了envelope和contents两部分的内容.其中headers和body是通过一个null line(clrf前什么都没有)分开的,对吧.一上来就应当把headers和body分开. c. 关于header field的处理,如果clrf后没有lwsp的话,就代表进入下一个header field的分析,对吧;否则,只是field-body的folding. d. message部分更多的是关于fileds的定义,而这些fields,应当都是属于header field,在某些情况下,header field的出现顺序是要符合文档的要求,对吗? |
| |||
| 引用:
真的建议你试试我的jparsec。如果需要,我会全力帮忙的。 代码:
这个java实现比haskell的那个标准库还多提供了些预定义的组合子。所以,也许不如haskell的优雅简洁,也许用起来麻烦些,但是,功能上,我可以自信地说,完全可以覆盖你的这个语法。这不是我自大,而是基于我对haskell parsec库的信心。 |
| ||||
| To ajoo: 你的组合子库,我看过你发的那篇帖子,也的确感觉功能很强大,表达能力很强.比我以前用的JavaCC要厉害的多.关于RFC822,其实也就是用ABNF描述的.关于ABNF,你可以看看这篇文档, RFC2234(中文): http://www.detian.org/rfc/RFC2234.txt 不知道,你的parsec能否coverABNF所有的语法表达能力. 然后关于Jparsec,我想要更多的了解它的运作机制. 在你的帖子中是关于一个四则运算的处理,里面用到了一些处理左递归的方法,用的是infixl,对吧.但是更具体的使用,我恐怕需要进一步和你讨论. 目前情况下,我的解决方案还是单独实现一个special parser,处理message.你的方案我需要更深入的了解,希望能得到你的大力帮助. |
| ||||
| 我也用递归下降做过一个 RFC822 Message 的 parser,主要的结构如下供参考。 1、整个 message 处理的基础是 MimeBodyPart; 2、每个 MimeBodyPart 包括一个首部列表和一个 MimeBodyPart 的列表;这是因为每个消息都包含一个首部,并且消息可能会嵌套 3、首部列表是一个 MessageHeaderField 的数组,由于 message 首部字段是有格式规定的,在解析时候根据字段名就能知道这个字段的类型,然后根据这个类型创建一个对应的 Field(从MessageHeaderField)派生; 4、MimeBodyPart 的列表是一个 MimeBodyPart 的数组。 在解析的时候根据分割符(空行或者 Mime 分割符)把 message 分割成各个部分,由对应的类去做进一步的解析。这样如果有新的首部字段,要么可以用一个通用字段处理类用常规的方式去解释它,也可以增加一个新的字段类去解释它。 下面是消息地址分析代码,这些代码并没有完全按照 BNF 编写,只作一个参考,但是它可以处理各种情况(其中用到的数据类型 AnsiString 就是 std: tring):代码:
|
| ||||
| 引用:
fields = dates source 1*destination *optional-field 目前,由于address,date-time都是采用recursion descent的方法做的.所以对于fileds的分析,我是否也是采用类似的方法呢?我不是很明白你的方法的特殊之处. 对于这个fields的语法描述,我不是很理解.在他的语法描述中,它刻意将dates,source等等都换了行,当然这个表示与语法定义无关.但我的疑惑是:既然定义成fields,那么每个字段怎么区分?好像在语法层我没有看到显式的定义.是不是也像long string folding一样,作为一个基本要求,在词法分析时就要注意呢?如果是这样的话,我觉得在词法分析的时候,每读到一个crlf且后面无lwsp就应当转入语法分析;每读到一个crlf且后面有lwsp的话,就应当继续进行词法分析.不过,如果这样子做的话,关于field的定义是什么呢?dates,source还是其他? |
| |||
| 引用:
你给的那段产生式,也可以直观地写。我写的那小段代码就可以cover了。 所以, 我认为cover这样的语法没有任何问题。 至于它的运作机制,我很乐意和你讨论。 等明天有空,我来仔细读一下这个rfc,看看能不能实现一个parser。不做任何语义动作,就检查一下格式就是了。咱们印证印证。 |