返回   cpper编程论坛 > 技术杂烩
注册账号 论坛帮助 会员列表 日历事件 搜索 今日新帖 标记版面已读

技术杂烩 找不到地方的技术问题?这里!

回复
 
LinkBack 主题工具 显示模式
  #1 (permalink)  
旧 2004-12-06
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认 关于RFC822 Message解析器的设计

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,语法中有大量的左递归和左因子.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #2 (permalink)  
旧 2004-12-06
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认

我说错了,目前完成的模块是address和date-time的分析.
然后Message中同样需要分析address和date-time
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #3 (permalink)  
旧 2004-12-06
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

对不起,我可能不是很理解你的意思。
我的理解是,你现在已经写好了header中的address和date-time的parser,但是你不知道怎么把同样的parser用到message body里面,是不是?
我写过类似的东西,很愿意和你探讨,但是需要更详细的信息。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #4 (permalink)  
旧 2004-12-07
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认

6. ADDRESS SPECIFICATION

6.1. SYNTAX

address = mailbox ; one addressee
/ group ; named list

group = phrase ":" [#mailbox] ";"

mailbox = addr-spec ; simple address
/ phrase route-addr ; name & addr-spec

route-addr = "<" [route] addr-spec ">"

route = 1#("@" domain) ":" ; path-relative

addr-spec = local-part "@" domain ; global address

local-part = word *("." word) ; uninterpreted
; case-preserved

domain = sub-domain *("." sub-domain)

sub-domain = domain-ref / domain-literal

domain-ref = atom ; symbolic reference

这个是RFC822中关于地址的语法定义,我们可以看出用ABNF描述的语法是很容易理解,但是存在左因子,当然我分析的时候,只要多lookahead一下就可以了.这个parser也不是很难实现,但由于只是用了一般的递归下降分析法,并不是Predicative的方法,所以只能检测出第一个错误,之后的错误无法检查出来,这个好像要涉及到错误恢复技术,对吧?
然后,同样我实现了Date-Time,也是用同样的方法实现的.
以上两个Parser,词法和语法都是单独设计的,其实有很多地方是可以重用的.
但是,你可以从这篇文档的Lexical Tokens部分看到他的定义很含糊;词法符号的定义有重.比如atom和DIGIT,他们就有重复的地方:数字.在词法层,我根本无法区分出'1'是作为DIGIT还是atom处理,我必须通过一些语法定义来获得相关的信息.
当然,目前这个并不是最重要的;在实现Message的时候,语法中有关于"Date-Time"和"address"语法范畴的调用,也就是意味着我必须在同一个文本中,区分出message和date-time.目前,我还没有想到万全之策.
而且,目前我的代码复用率真的很低,一旦加入新的rule,我的parser就要做很大的改动.之后,我看到了ajoo的Jparsec,觉得他的方案不错;但我就是不知道他的方案是否能完全cover到RFC822的语法定义;也就是说能否完全表达由ABNF所描述的RFC822的语法定义.
很高兴你对这个话题很感兴趣,加我MSN吧:amble_shisu@hotmail.com
我们一起讨论好了.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #5 (permalink)  
旧 2004-12-07
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

我写过完整的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.左递归其实可以消除的
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #6 (permalink)  
旧 2004-12-07
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认

1. 你的意思是说header和body本身就是分开的,不是在语法分析的时候分开的,对吧.
3. 看来error recovery基本不大可能
4. atom和digit的区分不经过产生式还是不能区分的,对吧;本来我就觉得词法层不应当太care具体的语法环境的
5. 是提取公共左因子,其实就是延迟候选式的选择,对吧.多lookahead一下也不错.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #7 (permalink)  
旧 2004-12-07
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认

PolyRandom,能在MSN上面和你具体讨论这个问题吗?
论坛发贴速度太慢了.告诉我你的MSN好了,或者你加我也可以.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #8 (permalink)  
旧 2004-12-08
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

引用:
作者: Meta
1. 你的意思是说header和body本身就是分开的,不是在语法分析的时候分开的,对吧.
3. 看来error recovery基本不大可能
4. atom和digit的区分不经过产生式还是不能区分的,对吧;本来我就觉得词法层不应当太care具体的语法环境的
5. 是提取公共左因子,其实就是延迟候选式的选择,对吧.多lookahead一下也不错.
1.对
2.不是,关键要弄清楚两点:
是否必要:因为大多数email是机器生成的,如果有错,报错就行了
确切定义:你要给你想recover的错误一个确切的定义,而不是简单的说recover,电脑很笨的
4.如果在词法层真得无法区分,那么就加一个新的TOKEN,叫ATOM_OR_DIGIT,然后把所有的ATOM和DIGIT放到这个里面去。在语法一层进一步检验是否正确
5.

我上班时候不用MSN的,何况我的MSN其实就在这个论坛里面 :P 只不过你没发现。我知道论坛的节奏比较慢,但是优点在于,大家可以分享,也比较持久。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #9 (permalink)  
旧 2004-12-08
高级会员
 
注册日期: 2002-09-15
帖子: 2,531
ajoo 正向着好的方向发展
默认

代码:
address = mailbox ; one addressee / group ; named list group = phrase ":" [#mailbox] ";" mailbox = addr-spec ; simple address / phrase route-addr ; name & addr-spec route-addr = "<" [route] addr-spec ">" route = 1#("@" domain) ":" ; path-relative addr-spec = local-part "@" domain ; global address local-part = word *("." word) ; uninterpreted ; case-preserved domain = sub-domain *("." sub-domain) sub-domain = domain-ref / domain-literal domain-ref = atom ; symbolic reference
我熟悉这个语法。
但是没有看明白你说的问题在哪里。
至于左递归。你是不是指的这个"#"?
如果是这样, 很简单的。用jparsec的sepBy1组合子就可以了。
举个例子:
代码:
final Parser comma = Terms.getParser(","); final Parser commas = comma.many1(); final Parser pound(Parser p){ return Parsers.sepBy1(commas, p); }
关于错误检测, 你可以可以看看jparsec的错误恢复能力。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #10 (permalink)  
旧 2004-12-08
高级会员
 
注册日期: 2002-09-15
帖子: 2,531
ajoo 正向着好的方向发展
默认

我说我不熟悉这个语法。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #11 (permalink)  
旧 2004-12-08
高级会员
 
注册日期: 2002-09-15
帖子: 2,531
ajoo 正向着好的方向发展
默认

大致写了一个对应的parser。你看看合适不合适。
没有带语义动作,如果你需要创建ast, 可以做相应的修改。

代码:
commas = comma.many1(); Parser list(final p){ return Parsers.sepBy(commas, p); } Parser list1(final P){ return Parsers.sepBy1(commas, p); } domain_ref = atom; sub_domain = Parsers(domain_ref, domain_literal); domain = sub_domain.seq(word_dot.seq(sub_domain).many()); addr_spec = local_part.folowedBy(word_at).seq(domain); route = list1(word_at.seq(domain)).followedBy(colon); route_addr = Parsers.between(lt, gt, route.optional().seq(addr_spec)); mailbox = Parsers.plus(adr_spec, phrase.seq(route_addr)); group = phrase.followedBy(colon).seq(list(mailbox).followedBy(semicolon)); address = Parsers.plus(mailbox, group);
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #12 (permalink)  
旧 2004-12-08
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认

引用:
作者: PolyRandom
1.对
2.不是,关键要弄清楚两点:
是否必要:因为大多数email是机器生成的,如果有错,报错就行了
确切定义:你要给你想recover的错误一个确切的定义,而不是简单的说recover,电脑很笨的
4.如果在词法层真得无法区分,那么就加一个新的TOKEN,叫ATOM_OR_DIGIT,然后把所有的ATOM和DIGIT放到这个里面去。在语法一层进一步检验是否正确
5.

我上班时候不用MSN的,何况我的MSN其实就在这个论坛里面 :P 只不过你没发现。我知道论坛的节奏比较慢,但是优点在于,大家可以分享,也比较持久。
2. 同意你的观点,目前只要报错就可以了.因为如果要实现recovery的话,产生式必须有严格的定义.
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的出现顺序是要符合文档的要求,对吗?
你的MSN在论坛里,那可真是大海捞针了;不过说不定哪一天就看到了.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #13 (permalink)  
旧 2004-12-08
polyrandom 的头像
超级版主
 
注册日期: 2002-09-03
帖子: 3,138
文章: 20
polyrandom 正向着好的方向发展
默认

a.body就是普通的text,不用考虑什么格式信息了。除非你要做MIME decode。
b.Y
c.Y,我这一步是单独作的。有时候把一个功能分成两步,实现起来会方便得多
d.的确,但是通常我不管顺序
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #14 (permalink)  
旧 2004-12-08
高级会员
 
注册日期: 2002-09-15
帖子: 2,531
ajoo 正向着好的方向发展
默认

引用:
以上两个Parser,词法和语法都是单独设计的,其实有很多地方是可以重用的. 但是,你可以从这篇文档的Lexical Tokens部分看到他的定义很含糊;词法符号的定义有重.比如atom和DIGIT,他们就有重复的地方:数字.在词法层,我根本无法区分出'1'是作为DIGIT还是atom处理,我必须通过一些语法定义来获得相关的信息.
当然,目前这个并不是最重要的;在实现Message的时候,语法中有关于"Date-Time"和"address"语法范畴的调用,也就是意味着我必须在同一个文本中,区分出message和date-time.目前,我还没有想到万全之策. 而且,目前我的代码复用率真的很低,一旦加入新的rule,我的parser就要做很大的改动.
组合子在这个方面正是特长。
真的建议你试试我的jparsec。如果需要,我会全力帮忙的。


代码:
之后,我看到了ajoo的Jparsec,觉得他的方案不错;但我就是不知道他的方案是否能完全cover到RFC822的语法定义;也就是说能否完全表达由ABNF所描述的RFC822的语法定义.
首先,我不能把parsec剽窃成我的方案。组合子逻辑已经是个很成熟的技术。我只不过在java中实现了一下而已。
这个java实现比haskell的那个标准库还多提供了些预定义的组合子。所以,也许不如haskell的优雅简洁,也许用起来麻烦些,但是,功能上,我可以自信地说,完全可以覆盖你的这个语法。这不是我自大,而是基于我对haskell parsec库的信心。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #15 (permalink)  
旧 2004-12-08
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认

To ajoo:
你的组合子库,我看过你发的那篇帖子,也的确感觉功能很强大,表达能力很强.比我以前用的JavaCC要厉害的多.关于RFC822,其实也就是用ABNF描述的.关于ABNF,你可以看看这篇文档, RFC2234(中文):
http://www.detian.org/rfc/RFC2234.txt
不知道,你的parsec能否coverABNF所有的语法表达能力.
然后关于Jparsec,我想要更多的了解它的运作机制.
在你的帖子中是关于一个四则运算的处理,里面用到了一些处理左递归的方法,用的是infixl,对吧.但是更具体的使用,我恐怕需要进一步和你讨论.
目前情况下,我的解决方案还是单独实现一个special parser,处理message.你的方案我需要更深入的了解,希望能得到你的大力帮助.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #16 (permalink)  
旧 2004-12-08
Innocentius 的头像
版主
 
注册日期: 2002-09-11
住址: 上海
帖子: 562
文章: 12
Innocentius 正向着好的方向发展
发送 MSN 消息给 Innocentius
默认

我也用递归下降做过一个 RFC822 Message 的 parser,主要的结构如下供参考。

1、整个 message 处理的基础是 MimeBodyPart;
2、每个 MimeBodyPart 包括一个首部列表和一个 MimeBodyPart 的列表;这是因为每个消息都包含一个首部,并且消息可能会嵌套
3、首部列表是一个 MessageHeaderField 的数组,由于 message 首部字段是有格式规定的,在解析时候根据字段名就能知道这个字段的类型,然后根据这个类型创建一个对应的 Field(从MessageHeaderField)派生;
4、MimeBodyPart 的列表是一个 MimeBodyPart 的数组。

在解析的时候根据分割符(空行或者 Mime 分割符)把 message 分割成各个部分,由对应的类去做进一步的解析。这样如果有新的首部字段,要么可以用一个通用字段处理类用常规的方式去解释它,也可以增加一个新的字段类去解释它。

下面是消息地址分析代码,这些代码并没有完全按照 BNF 编写,只作一个参考,但是它可以处理各种情况(其中用到的数据类型 AnsiString 就是 std:tring):

代码:
// 处理非 ASCII 文本,进行 BASE64 和 QP 解码 AnsiString DecodeNonAsciiText(const AnsiString & str, AnsiString & charset) { const ENCODE_BASE64='B'; const ENCODE_QUOTED_PRINTABLE='Q'; int encode_mode; int i; AnsiString result; try{ for(i=0;i<(int)str.size();i++){ if(str[i]=='='&&str[i+1]=='?'){ i+=2; charset=""; for(;i<(int)str.size()&&str[i]!='?';i++) charset+=str[i]; if(i==(int)str.size()) throw EAbort(); // decode failed i++; switch(CharToUpper(str[i])){ case ENCODE_BASE64: encode_mode=ENCODE_BASE64; break; case ENCODE_QUOTED_PRINTABLE: encode_mode=ENCODE_QUOTED_PRINTABLE; break; default: throw EAbort(); // decode failed } i++; if(str[i]=='?'){ i++; AnsiString t; for(;i<(int)str.size()&&str[i]!='?';i++) t+=str[i]; if(str[i]==(int)str.size()&&str[i+1]!='=') throw EAbort(); // decode failed if(encode_mode==ENCODE_BASE64) result+=Base64Decode(t); if(encode_mode==ENCODE_QUOTED_PRINTABLE) result+=QPDecode(t); i++; } else throw EAbort(); // decode failed } else result+=str[i]; } } catch(EAbort &){ charset=""; return str; } return result; } AnsiString EncodeNonAsciiText(const AnsiString & str) { AnsiString charset; return EncodeNonAsciiText(str,charset); } // 将 CRLF 去除 AnsiString & RemoveCRLF(AnsiString & str) { for(;;){ AnsiString::iterator p=str.begin(); for(;p!=str.end();p++){ if(*p=='\n'||*p=='\r'){ str.erase(p); break; } } if(p==str.end()) break; } return str; } AnsiString EncodeNonAsciiText(const AnsiString & str, const AnsiString & charset) { if(str.empty()||charset.empty()) return str; AnsiString result; result="=?"; result+=charset; result+="?B?"; result+=RemoveCRLF(Base64Encode(str)); result+="?="; return result; } // 合并首部分行(首部要求每行不超过78个字符) AnsiString UnwarpStringList(const AnsiStringList & list) { AnsiString result; for(int i=0;i<(int)list.size();i++) result+=AnsiTrim(list[i]); return result; } // 分行(考虑整字换行) void WarpStringList(const AnsiString & name, const AnsiStringList & value, AnsiStringList & dst, bool break_on_spaces) { if(name.empty()) return; if(value.empty()){ dst.push_back(name+": "); return; } AnsiString spaces="\t"; AnsiString s; for(int k=0;k<(int)value.size();k++){ if(k==0) s=name+": "+value[0]; else s=spaces+value[k]; if((int)s.size()>MAX_MESSAGE_LINE_LENGTH){ if(break_on_spaces){ while((int)s.size()>MAX_MESSAGE_LINE_LENGTH){ int i; for(i=MAX_MESSAGE_LINE_LENGTH;i>=0&&s[i]!=';'&&s[i]!=',';i--) ; if(i>=0) i++; else i=MAX_MESSAGE_LINE_LENGTH; dst.push_back(s.substr(0,i)); s.erase(0,i); if(!s.empty()) s=spaces+s; } if(!s.empty()) dst.push_back(s); } else{ char quote_char=0; int i=0; while(i<(int)s.size()){ if(quote_char==0&&(s[i]==';'||s[i]==',')){ i++; AnsiString p=s.substr(0,i); dst.push_back(p); s.erase(0,i); i=0; if(!s.empty()) s=spaces+s; } else{ if(s[i]==quote_char) quote_char=0; else{ if(s[i]=='\"') quote_char='\"'; if(s[i]=='<') quote_char='>'; if(s[i]=='(') quote_char=')'; } i++; } } if(!s.empty()) dst.push_back(s); } } else dst.push_back(s); } } // 在字符串两边加上双引号 AnsiString QuoteString(const AnsiString & str) { if(str.empty()) return "\"\""; AnsiString result; if(str[0]!='"') result="\""; result+=str; if(str[str.size()-1]!='"') result+="\""; return result; } // 在字符串两边去除双引号 AnsiString UnquoteString(const AnsiString & str) { if(str.empty()) return str; AnsiString result=str; if(result[0]=='"') result.erase(0,1); if(result[result.size()-1]=='"') result.erase(result.size()-1,1); return result; } // 处理混合格式的地址,包括一个名字和地址,如:“=?utf-8?B?5byg576957+8?= <yvyizh@163.com>” void EmailAddress::DecodingMixedAddress(const AnsiString & mixed_address) { _Charset=""; _Name=""; _Address=""; _IsGroup=false; AnsiString t; for(int i=0;i<(int)mixed_address.size();){ if(mixed_address[i]=='<'){ for(i++;i<(int)mixed_address.size()&&mixed_address[i]!='>';i++) _Address+=mixed_address[i]; for(i++;i<(int)mixed_address.size()&&CharIsSpace(mixed_address[i]);i++) ; } else if(mixed_address[i]=='('||mixed_address[i]=='"'){ char boundary; if(mixed_address[i]=='(') boundary=')'; else boundary='"'; for(i++;i<(int)mixed_address.size()&&mixed_address[i]!=boundary;i++) _Name+=mixed_address[i]; for(i++;i<(int)mixed_address.size()&&CharIsSpace(mixed_address[i]);i++) ; } else t+=mixed_address[i++]; } if(_Name.empty()&&_Address.empty()) _Address=t; else{ if(_Name.empty()) _Name=t; else if(_Address.empty()) _Address=t; } _Name=AnsiTrim(DecodeNonAsciiText(AnsiTrim(_Name),_Charset)); _IsGroup=_Name.find(':')!=_Name.npos; _Address=AnsiTrim(_Address); } // 处理多个混合格式的地址,如: // To: =?utf-8?B?5pyx55C06L6J?= <zhuqh@shanghai-air.com>, // =?utf-8?B?5byg576957+8?= <yvyizh@163.com>, // =?utf-8?B?5byg54ix6ZSm?= <zhangaijin@shanghai-air.com> void EmailAddressList::DecodingMixedAddressList(const AnsiStringList & mixed_address_list) { AnsiString s=UnwarpStringList(mixed_address_list); AnsiString t; for(int i=0;i<(int)s.size();i++){ if(s[i]==','){ AddAddress(t); t=""; } else t+=s[i]; } if(!t.empty()) AddAddress(t); }
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #17 (permalink)  
旧 2004-12-08
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认

引用:
作者: PolyRandom
a.body就是普通的text,不用考虑什么格式信息了。除非你要做MIME decode。
b.Y
c.Y,我这一步是单独作的。有时候把一个功能分成两步,实现起来会方便得多
d.的确,但是通常我不管顺序
关于c,多个field的处理.在语法中,他是这么定义的:
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还是其他?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #18 (permalink)  
旧 2004-12-08
高级会员
 
注册日期: 2002-09-15
帖子: 2,531
ajoo 正向着好的方向发展
默认

引用:
作者: Meta
To ajoo:
你的组合子库,我看过你发的那篇帖子,也的确感觉功能很强大,表达能力很强.比我以前用的JavaCC要厉害的多.关于RFC822,其实也就是用ABNF描述的.关于ABNF,你可以看看这篇文档, RFC2234(中文):
http://www.detian.org/rfc/RFC2234.txt
不知道,你的parsec能否coverABNF所有的语法表达能力.
然后关于Jparsec,我想要更多的了解它的运作机制.
在你的帖子中是关于一个四则运算的处理,里面用到了一些处理左递归的方法,用的是infixl,对吧.但是更具体的使用,我恐怕需要进一步和你讨论.
目前情况下,我的解决方案还是单独实现一个special parser,处理message.你的方案我需要更深入的了解,希望能得到你的大力帮助.
你给的连接我大致看了一下,它所包含的所有操作符(不定循环,指定循环,序列组,增式选择等等)都可以很简单地实现。
你给的那段产生式,也可以直观地写。我写的那小段代码就可以cover了。
所以, 我认为cover这样的语法没有任何问题。

至于它的运作机制,我很乐意和你讨论。
等明天有空,我来仔细读一下这个rfc,看看能不能实现一个parser。不做任何语义动作,就检查一下格式就是了。咱们印证印证。
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #19 (permalink)  
旧 2004-12-08
Meta 的头像
版主
 
注册日期: 2004-12-02
帖子: 226
文章: 5
Meta 正向着好的方向发展
默认

To Innocentius:
大概看了一下你的Code,你这个代码是MIME的?
RFC822只处理ASCII的Text.
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
  #20 (permalink)  
旧 2004-12-08
Innocentius 的头像
版主
 
注册日期: 2002-09-11
住址: 上海
帖子: 562
文章: 12
Innocentius 正向着好的方向发展
发送 MSN 消息给 Innocentius
默认

是的。不过如果仅仅是 RFC822 的也是没有问题的
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
回复时引用此帖
回复

书签

主题工具
显示模式

发帖规则
不可以发表新主题
不可以发表回复
不可以上传附件
不可以编辑自己的帖子

启用 BB 代码
论坛启用 表情符号
论坛启用 [IMG] 代码
论坛禁用 HTML 代码
Trackbacks are 启用
Pingbacks are 启用
Refbacks are 启用



所有时间均为格林尼治时间 +9。现在的时间是 08:35 AM


Powered by vBulletin® 版本 3.7.0
版权所有 ©2000 - 2009,Jelsoft Enterprises Ltd.
(C) Copy Right All Right Reserved 2001 - 2007

Search Engine Friendly URLs by vBSEO 3.1.0