上个月说到了自定义语言,不过在确定自己的语法后,遇到的第一个难题便是如何解析自己定义的语言,至于如何执行,是这之后的事情。

找一个语法解析器

    软件中有一点很重要,不要重复造轮子,等等,这话听起来有点怪,自定义语言不也是重复造轮子么?

    好吧,我承认我在重复造轮子,不过我的主要目的不是让自己的语言怎么怎么样,而是去更深入的理解那些编程语言,要是运气好,自己找的轮子能够流行起来,那自然更好了。

    因此,我要造的是语言,而不是语法解析器,所以不要重复造语法解析器,没有那个时间和精力去消耗在这上面。

    所以,随便找了个语法解析器:Grammatica

    那么为什么用这个而不用其它的?好吧,没有理由,仅仅是因为随便找了一下。哦,对了,还因为它支持我需要的LL(*)的语法结构。

使用之前

    在使用这个开源工具的.net版本之前,先要帮它修个小bug,当然这个小bug不是必须要修,只不过我的运用场景导致了了必须要修复。

    要修复什么问题哪?

    自定义异常

    建议大家都去读一下msdn上面的建议

    尤其是这一句:

Do make exceptions serializable. An exception must be serializable to work correctly across application domain and remoting boundaries.

    碰巧我的运行环境是在一个独立的AppDomain中,因此,脚本Parse所发生的异常会穿透域,而Grammatica的所有自定义异常都没有实现序列化,直接导致了序列化异常时出错,然后么,就杯具了,谁知道什么错了。

    因此,第一件事情,便是修复所有的自定义异常,正确实现序列化(不要以为标记了[Serializable]就已经实现了哦,异常的序列化可没这么简单,想进一步了解的话,可以看msdn,或者google,或者等我那天想到了写一下吧)。

设计语法

    一个好的语法绝对是一门语言成败的关键,不过,我目前还没掌握如何定义出一门好的语法。这里,先用一个滥语法来做个演示。

    首先,定义语言的一些Token,例如:

LAMBDA = "->"
LEFT_PAREN = "("
RIGHT_PAREN = ")"
LEFT_CURLY_BRACKET = "{"
RIGHT_CURLY_BRACKET = "}"
COLON = ":"
DOT = "."
ARGUMENT_SEPARATOR = ","

    和一些基本的字面量和保留字:

NUMBER = <<-?\d+(\.\d+)?>>
STRING_LITERAL = <<'([^'\r\n\\]|\\u[0-9a-f]{4}|\\[\\"'trn])*'>>
TRUE = "true"
FALSE = "false"
NULL_LITERAL = "null"
FUNC = "func"
NEW = "new"

    和剩下的标识符:

IDENTIFIER = <<[a-zA-Z]\w*>>

    这些是基础,来看看如何把这些Token组和起来(productions):

Expression = BasicExpression {MemberAccessExpression};

表达式就是一个基础表达式,加上0-N个成员访问表达式

MemberAccessExpression = "." MemberFunctionExpression;

成员访问表达式就是”.”加上一个成员或方法表达式

BasicExpression = LiteralExpression | VariableExpression | ExpressionGroup | NEWExpression;

基础表达式就是字面量表达式、变量表达式、表达式组、对象创建表达式中的任意一个

MemberFunctionExpression = FieldPropertyExpression | FunctionCallExpression;

成员或方法表达式就是字段/属性表达式或方法调用表达式中的一个

FieldPropertyExpression = IDENTIFIER;

字段/属性表达式就是标识符

FunctionCallExpression = IDENTIFIER "(" ArgumentList? ")";

方法调用表达式就是标识符+“(”+可能有参数列表+“)”

ArgumentList = Expression {"," Expression};

参数列表就是一个表达式,后面跟0-N个表达式

FUNCExpression = FUNC "(" ParameterList? ")" "->" Expression;

函数表达式就是“func”+”(”+可能有参数列表+“)”+”->”+表达式

ParameterList = IDENTIFIER {"," IDENTIFIER};

参数列表就是一个标识符,后面跟0-N个标识符

NEWExpression = NEW "{" PropertyValueExpression { "," PropertyValueExpression } "}";

对象创建表达式就是”new”+”{”+1-N个属性值表达式+”}”

PropertyValueExpression = IDENTIFIER ":" Expression;

属性值表达式就是一个标识符+”:”+表达式

ExpressionGroup = "(" Expression ")";

表达式组就是”(”+表达式+”)”

VariableExpression = IDENTIFIER;

变量表达式就是标识符

LiteralExpression = NUMBER | STRING_LITERAL | TRUE | FALSE | NULL_LITERAL;

字面量表达式就是数字、字符串、true、false、null中的任意一个

    看到这里,如果没有看晕,那么恭喜你,太有天赋了,为了理解这些,我足足花了一个星期的时间。

看看能解析什么

    为了让大家知道上面写了这么大一串,究竟发生了什么作用,我们可以从简到繁的写几个例子:

解析:a.b.c
结果:变量a.字段b.字段c

解析:foo.bar(x,y)
结果:变量foo.方法bar(参数列表:变量x,变量y)

解析:foo.bar().foobar
结果:变量foo.方法bar().字段foobar

解析:new { firstName: ‘Zhenway’, lastName: ‘Yan’ }
结果:创建对象,字段firstName的值为“Zhenway”,字段lastName的值为“Yan”

解析:list.select(func(item)->item.abc)
结果:变量list.方法select(参数列表:lambda:形参列表:item -> 变量item.字段abc)

    再来个复杂点的

解析:new { firstName: ‘Zhenway’, lastName: ‘Yan’, toString: func() –> ‘Zhenway Yan’ }
结果:创建对象,字段firstName的值为“Zhenway”,字段lastName的值为“Yan”,字段toString是个lambda:形参列表:无 -> 字符串字面量“Zhenway Yan”

解析:x.f(x.g(x.h(1)))
结果:变量x.方法f(参数列表:变量x.方法g(参数列表:变量x.方法h()))

    有没有发现了什么?还没?再来一个:

new { name: new { firstName: ‘Zhenway’, lastName: ‘Yan’, toString: func() –> ‘Zhenway Yan’ }, address: new { country:’China’ province: 'Shanghai', toString: func() –> 'Shanghai China’ } }

    现在发现什么了?

    没错这个结构可以一直嵌套下去,这就是表达式带来的无穷的想象力。

还缺什么

    有没有发现缺了什么?现在的定义是在太少了,很多东西无法表达,例如name的toString其实永远是firstName+lastName,看缺了什么,让我们无法这样定义:

  • 最明显的是“+”,+、-、*、/、%这类表达式尚未定义(当然你要想的全的话,还有and、or、xor等等)
  • 其次是没有this,无法表达当前对象(这里,我的面向对象的惯性思维又冒出来了…)

    如果,添加一个Token:THIS=”this”,并且加一个表达式:

THISExpression = THIS;

this表达式就是”this”

    再修改一下BasicExpression,添加上一个或THISExpression,那么我们就可以在完全兼容原有语法的基础上,添加了对this的支持,例如:

new { item: ‘abc’, getItemLength: func() -> this.item.length }

    是不是很Cool,想象一下,当你有个新Idea,并且实现时,你的所有表达式都可能从中获益,而且对老的表达式又完全兼容。

下集预告

    这么Cool的功能如何实现哪?Oh, no!说了半天都是理论啊,具体如何实现,请听下回分解。

posted on 2011-03-09 17:16  Zhenway  阅读(1602)  评论(1编辑  收藏  举报