介绍C#ParsingLibrary

C# Parsing Library 是一个LL解析器产生框架,可以在C#中模拟ENBF文法定义。设计思路来自于Boost.Spirit,一个C++解析器框架。

一)C# Parsing Library:Parser 基本概念

a) 文法定义举例:P ::= a b    C#用法:P = a + b    序列

b) 文法定义举例:P ::= a | b  C#用法:P = a | b    选择

c) 文法定义举例:P ::= a *    C#用法:P = a.Star   0..n次匹配

d) 文法定义举例:P ::= a +    C#用法:P = a.Plus   1..n次匹配

e) 文法定义举例:P ::= a ?    C#用法:P = a.Opt    0..1次匹配

P为Parser类型,是解析器的抽象基类,它定义了一个抽象的Parse方法:

 
 
 
  1. bool Parse(Scanner scanner);

Scanner类主要存储一个字符串输入,及一个光标位置,光标随着解析的进行向前移动。

例子:一个整数解析器, 定义为一个可选的符号后面跟若干数字:

 
 
 
  1. Parser signed = (Parser.Lit('+') | '-').Opt;
  2. Parser p = (signed + Parser.DigitChar.Plus).Lexeme;
  3. bool success = p.Parse(new Scanner("-123"));

其中,Lit表示常量,Lexeme表示为词法分析,即不忽略空格。

二)C# Parsing Library:ParserRef

一个常用的四则运算表达式文法:

 
 
 
  1. group      ::= '(' expression ')'
  2. factor     ::= integer | group
  3. term       ::= factor (('*' factor) | ('/' factor))*
  4. expression ::= term (('+' term) | ('-' term))*

用下面的方法是错误的:

 
 
 
  1. Parser group; //  Parser 是抽象类,无法 new
  2. Parser factor;
  3. factor = Parser.Int | group; // 错误! group没有初始化!

但是使用ParserRef 就可以了:

 
 
 
  1. ParserRef group = new ParserRef();
  2. ParserRef factor = new ParserRef();
  3. factor.Parser = Parser.Int | group; 

完整的定义如下:

 
 
 
  1. ParserRef group = new ParserRef();
  2. ParserRef factor = new ParserRef();
  3. ParserRef term = new ParserRef();
  4. ParserRef expression = new ParserRef();
  5. group.Parser = '(' + expression + ')';
  6. factor.Parser = Parser.Int
  7.               | group;
  8. term.Parser     = factor + 
  9.                   ( ('*' + factor)
  10.                   | ('/' + factor)
  11.                   ).Star;
  12. expression.Parser = term + 
  13.                     ( ('+' + term)
  14.                     | ('-' + term)
  15.                     ).Star;

三)C# Parsing Library:Rule和语义支持

和 spirit一样,通过对[]的重载,实现对语义的支持。一般的parser的Action类型为Action< string>, 即 void Action(string s)。s为该parser匹配的内容。如果要支持上下文, 就要使用Rule了. Rule带有一个模板参数T,表示属性类型。Action类型为Func< T,T,T> 即 T Action(T lhs, T rhs)。对于以下的简单规则:

 
 
 
  1. LeftRule := RightRule [ Action(lhs, rhs) ]

其语义为:LeftRule.Attribute = Action(LeftRule.Attribute, RightRule.Attribute).

上面的四则运算示例可修改如下:

 
 
 
  1. Grammar< int> grammar  = new Grammar< int>();
  2. Rule< int> group = new Rule< int>(grammar);
  3. Rule< int> factor = new Rule< int>(grammar);
  4. Rule< int> term = new Rule< int>(grammar);
  5. Rule< int> expression  = new Rule< int>(grammar);
  6. Rule< int> start = new Rule< int>(grammar);
  7. grammar.Start = start;
  8. group.Parser = '(' + expression [ (lhs, rhs) => rhs ] + ')';
  9. factor.Parser = Parser.IntValue [ v => grammar.Ret(v) ]  // (#1)
  10.               | group [ (lhs, rhs) => rhs ];
  11. term.Parser = factor [ (lhs, rhs) => rhs ] + 
  12.               ( ('*' + factor [ (lhs, rhs) => lhs * rhs ])
  13.               | ('/' + factor [ (lhs, rhs) => lhs / rhs ])
  14.               ).Star;
  15. expression.Parser = term [ (lhs, rhs) => rhs ] + 
  16.                     ( ('+' + term [ (lhs, rhs) => lhs + rhs ])
  17.                     | ('-' + term [ (lhs, rhs) => lhs - rhs ])
  18.                     ).Star;
  19. start.Parser = expression [ (lhs, rhs) => rhs ] + Parser.End;
  20. int result;
  21. bool success = grammar.Parse("10 + 20 + 30 * (40 + 50)", out result);
  22. if (success) Console.WriteLine(result);

说明:

对于一般的Parser,语义动作中并不能有返回值,因为它不知道属性的确切类型,要支持属性,必须使用 Grammar.Ret().

在我自己实现以前,大致搜了一下,在CodeProject上有一个类似的实现,也是模仿Boost.Spirit,不过它的语义处理采用C#的事件机制,用起来极不方便。这个项目我刚刚把它发布在google code 上面,项目主页:http://code.google.com/p/csparsing/。当然它还远远不够成熟。

标题名称:介绍C#ParsingLibrary
标题URL:http://www.shufengxianlan.com/qtweb/news24/352524.html

网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等

广告

声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联